@perspective-dev/viewer 5.0.0 → 5.2.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 +9 -9
- package/dist/cdn/perspective-viewer.js.map +4 -4
- package/dist/css/botanical.css +1 -1
- package/dist/css/dracula.css +1 -1
- package/dist/css/gruvbox-dark.css +1 -1
- package/dist/css/gruvbox.css +1 -1
- package/dist/css/icons.css +1 -1
- package/dist/css/intl/de.css +1 -1
- package/dist/css/intl/es.css +1 -1
- package/dist/css/intl/fr.css +1 -1
- package/dist/css/intl/ja.css +1 -1
- package/dist/css/intl/pt.css +1 -1
- package/dist/css/intl/zh.css +1 -1
- package/dist/css/intl.css +1 -1
- package/dist/css/monokai.css +1 -1
- package/dist/css/phosphor.css +1 -1
- package/dist/css/pro-dark.css +1 -1
- package/dist/css/pro.css +1 -1
- package/dist/css/solarized-dark.css +1 -1
- package/dist/css/solarized.css +1 -1
- package/dist/css/themes.css +1 -1
- package/dist/css/vaporwave.css +1 -1
- package/dist/docs/perspective-docs.json +1 -0
- package/dist/esm/column-format.d.ts +19 -28
- package/dist/esm/perspective-viewer.d.ts +2 -0
- package/dist/esm/perspective-viewer.inline.js +8 -8
- package/dist/esm/perspective-viewer.inline.js.map +4 -4
- package/dist/esm/perspective-viewer.js +9 -9
- package/dist/esm/perspective-viewer.js.map +4 -4
- package/dist/esm/providers.d.ts +79 -0
- package/dist/esm/ts-rs/CompactDisplay.d.ts +5 -0
- package/dist/esm/ts-rs/CurrencyCode.d.ts +1 -0
- package/dist/esm/ts-rs/CurrencyDisplay.d.ts +1 -0
- package/dist/esm/ts-rs/CurrencyNumberFormatStyle.d.ts +8 -0
- package/dist/esm/ts-rs/CurrencySign.d.ts +1 -0
- package/dist/esm/ts-rs/CustomDatetimeFormat.d.ts +1 -0
- package/dist/esm/ts-rs/CustomDatetimeStyleConfig.d.ts +54 -0
- package/dist/esm/ts-rs/CustomNumberFormatConfig.d.ts +34 -0
- package/dist/esm/ts-rs/DatetimeColorMode.d.ts +1 -0
- package/dist/esm/ts-rs/DatetimeFormatType.d.ts +6 -0
- package/dist/esm/ts-rs/FormatMode.d.ts +1 -0
- package/dist/esm/ts-rs/FormatUnit.d.ts +1 -0
- package/dist/esm/ts-rs/Notation.d.ts +17 -0
- package/dist/esm/ts-rs/NumberFormatStyle.d.ts +18 -0
- package/dist/esm/ts-rs/PanelViewerConfig.d.ts +43 -1
- package/dist/esm/ts-rs/PluginStaticConfig.d.ts +35 -0
- package/dist/esm/ts-rs/RestoreOptions.d.ts +19 -0
- package/dist/esm/ts-rs/RoundingMode.d.ts +1 -0
- package/dist/esm/ts-rs/RoundingPriority.d.ts +1 -0
- package/dist/esm/ts-rs/SignDisplay.d.ts +1 -0
- package/dist/esm/ts-rs/SimpleDatetimeFormat.d.ts +1 -0
- package/dist/esm/ts-rs/SimpleDatetimeStyleConfig.d.ts +24 -0
- package/dist/esm/ts-rs/SplitRollupMode.d.ts +9 -0
- package/dist/esm/ts-rs/StringColorMode.d.ts +1 -0
- package/dist/esm/ts-rs/TrailingZeroDisplay.d.ts +1 -0
- package/dist/esm/ts-rs/Unit.d.ts +1 -0
- package/dist/esm/ts-rs/UnitDisplay.d.ts +1 -0
- package/dist/esm/ts-rs/UnitNumberFormatStyle.d.ts +6 -0
- package/dist/esm/ts-rs/UseGrouping.d.ts +1 -0
- package/dist/esm/ts-rs/ViewerConfig.d.ts +43 -1
- package/dist/esm/ts-rs/ViewerConfigInitial.d.ts +175 -0
- package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +72 -0
- package/dist/esm/ts-rs/WindowSort.d.ts +7 -0
- package/dist/esm/ts-rs/WindowSortDir.d.ts +6 -0
- package/dist/esm/ts-rs/WindowSpec.d.ts +47 -0
- package/dist/esm/ts-rs/Windows.d.ts +10 -0
- package/dist/esm/ts-rs/WorkspaceConfigUpdate.d.ts +7 -6
- package/dist/wasm/perspective-viewer.d.ts +222 -26
- package/dist/wasm/perspective-viewer.js +378 -125
- package/dist/wasm/perspective-viewer.wasm +0 -0
- package/dist/wasm/perspective-viewer.wasm.d.ts +18 -15
- package/package.json +2 -1
- package/src/css/_viewer_bundle.css +1 -0
- package/src/css/column-selector.css +9 -0
- package/src/css/column-settings-panel.css +67 -2
- package/src/css/column-style.css +4 -3
- package/src/css/config-selector.css +60 -4
- package/src/css/containers/context-menu.css +12 -6
- package/src/css/containers/tabs.css +2 -2
- package/src/css/form/code-editor.css +2 -3
- package/src/css/form/mirrored-textarea.css +81 -0
- package/src/css/viewer.css +336 -0
- package/src/rust/agent/client/mod.rs +19 -0
- package/src/rust/agent/client/protocol.rs +320 -0
- package/src/rust/agent/client/transport.rs +287 -0
- package/src/rust/agent/client/turn.rs +174 -0
- package/src/rust/agent/config.rs +159 -0
- package/src/rust/agent/docs.rs +293 -0
- package/src/rust/agent/markdown/block.rs +509 -0
- package/src/rust/agent/markdown/entity.rs +52 -0
- package/src/rust/agent/markdown/events.rs +71 -0
- package/src/rust/agent/markdown/inline.rs +497 -0
- package/src/rust/agent/markdown/mod.rs +466 -0
- package/src/rust/agent/mod.rs +23 -0
- package/src/rust/agent/preamble.md +16 -0
- package/src/rust/agent/runtime.rs +201 -0
- package/src/rust/agent/slot.rs +236 -0
- package/src/rust/agent/tools.rs +1110 -0
- package/src/rust/components/chat_panel.rs +289 -0
- package/src/rust/components/column_selector/active_column.rs +21 -27
- package/src/rust/components/column_selector/column_selector_column_row.rs +73 -0
- package/src/rust/components/column_selector/config_selector.rs +83 -8
- package/src/rust/components/column_selector/expr_edit_button.rs +7 -1
- package/src/rust/components/column_selector/inactive_column.rs +8 -1
- package/src/rust/components/column_selector.rs +27 -3
- package/src/rust/components/column_settings_sidebar/style_tab.rs +2 -1
- package/src/rust/components/column_settings_sidebar/window_tab.rs +34 -0
- package/src/rust/components/column_settings_sidebar.rs +163 -16
- package/src/rust/components/containers/dragdrop_list.rs +110 -3
- package/src/rust/components/containers/sidebar.rs +99 -22
- package/src/rust/components/containers/split_panel.rs +6 -0
- package/src/rust/components/editable_header.rs +2 -0
- package/src/rust/components/form/code_editor.rs +14 -23
- package/src/rust/components/form/debug.rs +8 -5
- package/src/rust/components/form/mirrored_textarea.rs +165 -0
- package/src/rust/components/form/mod.rs +1 -0
- package/src/rust/components/main_panel.rs +5 -0
- package/src/rust/components/mod.rs +3 -0
- package/src/rust/components/panel_menu.rs +7 -0
- package/src/rust/components/panel_tab.rs +5 -0
- package/src/rust/components/portal.rs +7 -0
- package/src/rust/components/settings_panel.rs +80 -2
- package/src/rust/components/viewer/msg.rs +2 -0
- package/src/rust/components/viewer/panels.rs +9 -14
- package/src/rust/components/viewer/render.rs +14 -0
- package/src/rust/components/viewer/settings.rs +33 -1
- package/src/rust/components/viewer.rs +2 -0
- package/src/rust/components/window_editor.rs +985 -0
- package/src/rust/config/datetime_column_style/custom.rs +17 -0
- package/src/rust/config/datetime_column_style/simple.rs +10 -0
- package/src/rust/config/number_string_format.rs +33 -0
- package/src/rust/config/options.rs +18 -0
- package/src/rust/config/plugin_static_config.rs +120 -5
- package/src/rust/config/viewer_config.rs +220 -1
- package/src/rust/config/workspace_config.rs +7 -6
- package/src/rust/custom_elements/viewer.rs +209 -18
- package/src/rust/custom_events.rs +29 -0
- package/src/rust/lib.rs +17 -1
- package/src/rust/presentation/column_locator.rs +16 -1
- package/src/rust/presentation.rs +8 -0
- package/src/rust/queries/columns_iter_set.rs +7 -1
- package/src/rust/queries/get_viewer_config.rs +5 -1
- package/src/rust/renderer/dispatch.rs +85 -58
- package/src/rust/renderer.rs +34 -1
- package/src/rust/session/column_defaults_update.rs +18 -0
- package/src/rust/session/drag_drop_update.rs +18 -0
- package/src/rust/session/metadata.rs +64 -9
- package/src/rust/session/replace_expression_update.rs +2 -0
- package/src/rust/session.rs +7 -5
- package/src/rust/tasks/create_panel.rs +18 -8
- package/src/rust/tasks/edit_window.rs +155 -0
- package/src/rust/tasks/mod.rs +2 -0
- package/src/rust/tasks/restore_panel.rs +34 -17
- package/src/rust/tasks/sync_update_panels.rs +7 -23
- package/src/rust/utils/browser/dragdrop.rs +12 -0
- package/src/rust/utils/browser/tests/debounce.rs +49 -0
- package/src/rust/utils/debounce.rs +76 -27
- package/src/rust/workspace.rs +112 -20
- package/src/svg/pin-icon.svg +5 -0
- package/src/themes/icons.css +1 -0
- package/src/themes/intl/de.css +23 -0
- package/src/themes/intl/es.css +23 -0
- package/src/themes/intl/fr.css +23 -0
- package/src/themes/intl/ja.css +23 -0
- package/src/themes/intl/pt.css +23 -0
- package/src/themes/intl/zh.css +23 -0
- package/src/themes/intl.css +26 -1
- package/src/ts/column-format.ts +67 -46
- package/src/ts/perspective-viewer.ts +2 -0
- package/src/ts/providers.ts +96 -0
- package/src/ts/ts-rs/CompactDisplay.ts +3 -0
- package/src/ts/ts-rs/CurrencyCode.ts +3 -0
- package/src/ts/ts-rs/CurrencyDisplay.ts +3 -0
- package/src/ts/ts-rs/CurrencyNumberFormatStyle.ts +6 -0
- package/src/ts/ts-rs/CurrencySign.ts +3 -0
- package/src/ts/ts-rs/CustomDatetimeFormat.ts +3 -0
- package/src/ts/ts-rs/CustomDatetimeStyleConfig.ts +54 -0
- package/src/ts/ts-rs/CustomNumberFormatConfig.ts +25 -0
- package/src/ts/ts-rs/DatetimeColorMode.ts +3 -0
- package/src/ts/ts-rs/DatetimeFormatType.ts +8 -0
- package/src/ts/ts-rs/FormatMode.ts +3 -0
- package/src/ts/ts-rs/FormatUnit.ts +3 -0
- package/src/ts/ts-rs/Notation.ts +11 -0
- package/src/ts/ts-rs/NumberFormatStyle.ts +12 -0
- package/src/ts/ts-rs/PanelViewerConfig.ts +48 -1
- package/src/ts/ts-rs/PluginStaticConfig.ts +36 -1
- package/src/ts/ts-rs/RestoreOptions.ts +20 -0
- package/src/ts/ts-rs/RoundingMode.ts +3 -0
- package/src/ts/ts-rs/RoundingPriority.ts +3 -0
- package/src/ts/ts-rs/SignDisplay.ts +3 -0
- package/src/ts/ts-rs/SimpleDatetimeFormat.ts +3 -0
- package/src/ts/ts-rs/SimpleDatetimeStyleConfig.ts +25 -0
- package/src/ts/ts-rs/SplitRollupMode.ts +11 -0
- package/src/ts/ts-rs/StringColorMode.ts +3 -0
- package/src/ts/ts-rs/TrailingZeroDisplay.ts +3 -0
- package/src/ts/ts-rs/Unit.ts +3 -0
- package/src/ts/ts-rs/UnitDisplay.ts +3 -0
- package/src/ts/ts-rs/UnitNumberFormatStyle.ts +5 -0
- package/src/ts/ts-rs/UseGrouping.ts +3 -0
- package/src/ts/ts-rs/ViewerConfig.ts +48 -1
- package/src/ts/ts-rs/ViewerConfigInitial.ts +164 -0
- package/src/ts/ts-rs/ViewerConfigUpdate.ts +81 -2
- package/src/ts/ts-rs/WindowSort.ts +9 -0
- package/src/ts/ts-rs/WindowSortDir.ts +8 -0
- package/src/ts/ts-rs/WindowSpec.ts +47 -0
- package/src/ts/ts-rs/Windows.ts +10 -0
- package/src/ts/ts-rs/WorkspaceConfigUpdate.ts +7 -6
- /package/dist/wasm/snippets/{perspective-viewer-daeef4ceb066e6c7 → perspective-viewer-02e461f3d7062b26}/inline0.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-daeef4ceb066e6c7 → perspective-viewer-02e461f3d7062b26}/inline1.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-daeef4ceb066e6c7 → perspective-viewer-02e461f3d7062b26}/inline2.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-daeef4ceb066e6c7 → perspective-viewer-02e461f3d7062b26}/inline3.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-daeef4ceb066e6c7 → perspective-viewer-02e461f3d7062b26}/inline4.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-daeef4ceb066e6c7 → perspective-viewer-02e461f3d7062b26}/inline5.js +0 -0
|
@@ -43,6 +43,10 @@ pub struct InactiveColumnProps {
|
|
|
43
43
|
#[prop_or_default]
|
|
44
44
|
pub is_expression: bool,
|
|
45
45
|
|
|
46
|
+
/// Whether this column is a window column.
|
|
47
|
+
#[prop_or_default]
|
|
48
|
+
pub is_window: bool,
|
|
49
|
+
|
|
46
50
|
/// Session metadata snapshot — threaded from `SessionProps`.
|
|
47
51
|
pub metadata: SessionMetadataRc,
|
|
48
52
|
|
|
@@ -72,6 +76,7 @@ impl PartialEq for InactiveColumnProps {
|
|
|
72
76
|
&& self.name == rhs.name
|
|
73
77
|
&& self.is_editing == rhs.is_editing
|
|
74
78
|
&& self.is_expression == rhs.is_expression
|
|
79
|
+
&& self.is_window == rhs.is_window
|
|
75
80
|
&& self.metadata == rhs.metadata
|
|
76
81
|
&& self.view_config == rhs.view_config
|
|
77
82
|
}
|
|
@@ -148,6 +153,7 @@ impl Component for InactiveColumn {
|
|
|
148
153
|
.callback(|event: MouseEvent| MouseEnter(event.which() == 0));
|
|
149
154
|
|
|
150
155
|
let is_expression = ctx.props().is_expression;
|
|
156
|
+
let is_window = ctx.props().is_window;
|
|
151
157
|
|
|
152
158
|
let mut is_active_class = ctx.props().renderer.metadata().select_mode.css();
|
|
153
159
|
is_active_class.push("shift-alt-icon");
|
|
@@ -179,7 +185,8 @@ impl Component for InactiveColumn {
|
|
|
179
185
|
name={ctx.props().name.clone()}
|
|
180
186
|
on_open_expr_panel={&ctx.props().on_open_expr_panel}
|
|
181
187
|
{is_expression}
|
|
182
|
-
|
|
188
|
+
{is_window}
|
|
189
|
+
is_disabled={!(is_expression || is_window)}
|
|
183
190
|
is_editing={ctx.props().is_editing}
|
|
184
191
|
/>
|
|
185
192
|
</div>
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
mod active_column;
|
|
14
14
|
mod add_expression_button;
|
|
15
15
|
mod aggregate_selector;
|
|
16
|
+
mod column_selector_column_row;
|
|
16
17
|
mod config_selector;
|
|
17
18
|
mod empty_column;
|
|
18
19
|
mod expr_edit_button;
|
|
@@ -25,6 +26,7 @@ mod sort_column;
|
|
|
25
26
|
use std::iter::*;
|
|
26
27
|
use std::rc::Rc;
|
|
27
28
|
|
|
29
|
+
pub use column_selector_column_row::*;
|
|
28
30
|
pub use empty_column::*;
|
|
29
31
|
pub use invalid_column::*;
|
|
30
32
|
use perspective_client::config::ViewConfig;
|
|
@@ -40,6 +42,7 @@ use super::containers::scroll_panel::*;
|
|
|
40
42
|
use super::containers::split_panel::{Orientation, SplitPanel};
|
|
41
43
|
use crate::components::column_dropdown::{ColumnDropDownElement, ColumnDropDownPortal};
|
|
42
44
|
use crate::components::containers::scroll_panel_item::ScrollPanelItem;
|
|
45
|
+
use crate::config::PluginStaticConfig;
|
|
43
46
|
use crate::presentation::{ColumnLocator, DragDropContainer, Presentation};
|
|
44
47
|
use crate::queries::{ActiveColumnState, ActiveColumnStateData, ColumnsIteratorSet};
|
|
45
48
|
use crate::renderer::*;
|
|
@@ -59,6 +62,10 @@ pub struct ColumnSelectorProps {
|
|
|
59
62
|
/// Value props threaded from root's `SessionProps` / `RendererProps`.
|
|
60
63
|
pub has_table: Option<TableLoadState>,
|
|
61
64
|
pub named_column_count: usize,
|
|
65
|
+
|
|
66
|
+
/// The ACTIVE plugin's declared contract — see the identically named
|
|
67
|
+
/// prop on `SettingsPanelProps`.
|
|
68
|
+
pub plugin_static_config: Rc<PluginStaticConfig>,
|
|
62
69
|
pub view_config: PtrEqRc<ViewConfig>,
|
|
63
70
|
pub drag_column: Option<String>,
|
|
64
71
|
|
|
@@ -101,6 +108,7 @@ impl PartialEq for ColumnSelectorProps {
|
|
|
101
108
|
self.selected_column == rhs.selected_column
|
|
102
109
|
&& self.has_table == rhs.has_table
|
|
103
110
|
&& self.named_column_count == rhs.named_column_count
|
|
111
|
+
&& self.plugin_static_config == rhs.plugin_static_config
|
|
104
112
|
&& self.view_config == rhs.view_config
|
|
105
113
|
&& self.drag_column == rhs.drag_column
|
|
106
114
|
&& self.metadata == rhs.metadata
|
|
@@ -344,6 +352,7 @@ impl Component for ColumnSelector {
|
|
|
344
352
|
drag_column={ctx.props().drag_column.clone()}
|
|
345
353
|
metadata={metadata.clone()}
|
|
346
354
|
selected_theme={ctx.props().selected_theme.clone()}
|
|
355
|
+
plugin_static_config={ctx.props().plugin_static_config.clone()}
|
|
347
356
|
{presentation}
|
|
348
357
|
{renderer}
|
|
349
358
|
{session}
|
|
@@ -367,7 +376,9 @@ impl Component for ColumnSelector {
|
|
|
367
376
|
let column_dropdown = self.column_dropdown.clone();
|
|
368
377
|
let is_editing = matches!(
|
|
369
378
|
&ctx.props().selected_column,
|
|
370
|
-
Some(ColumnLocator::Table(x))
|
|
379
|
+
Some(ColumnLocator::Table(x))
|
|
380
|
+
| Some(ColumnLocator::Expression(x))
|
|
381
|
+
| Some(ColumnLocator::Window(x))
|
|
371
382
|
if x == &key );
|
|
372
383
|
|
|
373
384
|
// Compute metadata-derived props here so that changes to
|
|
@@ -392,10 +403,15 @@ impl Component for ColumnSelector {
|
|
|
392
403
|
.map(|n| metadata.is_column_expression(n))
|
|
393
404
|
.unwrap_or(false);
|
|
394
405
|
|
|
406
|
+
let is_window = name
|
|
407
|
+
.get_name()
|
|
408
|
+
.map(|n| metadata.is_column_window(n))
|
|
409
|
+
.unwrap_or(false);
|
|
410
|
+
|
|
395
411
|
let can_render_styles =
|
|
396
412
|
name.get_name().is_some() && renderer.can_render_column_styles();
|
|
397
413
|
|
|
398
|
-
let show_edit_btn = is_expression || can_render_styles;
|
|
414
|
+
let show_edit_btn = is_expression || is_window || can_render_styles;
|
|
399
415
|
let on_open_expr_panel = &ctx.props().on_open_expr_panel;
|
|
400
416
|
html_nested! {
|
|
401
417
|
<ScrollPanelItem {key} {size_hint}>
|
|
@@ -405,6 +421,7 @@ impl Component for ColumnSelector {
|
|
|
405
421
|
{is_aggregated}
|
|
406
422
|
{is_editing}
|
|
407
423
|
{is_expression}
|
|
424
|
+
{is_window}
|
|
408
425
|
{show_edit_btn}
|
|
409
426
|
{col_type}
|
|
410
427
|
view_config={config.clone()}
|
|
@@ -425,12 +442,18 @@ impl Component for ColumnSelector {
|
|
|
425
442
|
|
|
426
443
|
let mut inactive_children: Vec<_> = columns_iter
|
|
427
444
|
.expression()
|
|
445
|
+
.chain(columns_iter.window())
|
|
428
446
|
.chain(columns_iter.inactive())
|
|
429
447
|
.enumerate()
|
|
430
448
|
.map(|(idx, vc)| {
|
|
431
449
|
let selected_column = ctx.props().selected_column.as_ref();
|
|
432
|
-
let is_editing = matches!(
|
|
450
|
+
let is_editing = matches!(
|
|
451
|
+
selected_column,
|
|
452
|
+
Some(ColumnLocator::Expression(x)) | Some(ColumnLocator::Window(x))
|
|
453
|
+
if x.as_str() == vc.name
|
|
454
|
+
);
|
|
433
455
|
let is_expression = metadata.is_column_expression(vc.name);
|
|
456
|
+
let is_window = metadata.is_column_window(vc.name);
|
|
434
457
|
html_nested! {
|
|
435
458
|
<ScrollPanelItem key={vc.name} size_hint=28.0>
|
|
436
459
|
<InactiveColumn
|
|
@@ -439,6 +462,7 @@ impl Component for ColumnSelector {
|
|
|
439
462
|
name={vc.name.to_owned()}
|
|
440
463
|
{is_editing}
|
|
441
464
|
{is_expression}
|
|
465
|
+
{is_window}
|
|
442
466
|
view_config={config.clone()}
|
|
443
467
|
metadata={metadata.clone()}
|
|
444
468
|
onselect={&onselect}
|
|
@@ -326,7 +326,8 @@ pub fn StyleTab(props: &StyleTabProps) -> Html {
|
|
|
326
326
|
},
|
|
327
327
|
};
|
|
328
328
|
|
|
329
|
-
|
|
329
|
+
let key = format!("{}::{}", props.column_name, keys.join("+"));
|
|
330
|
+
Some(html! { <fieldset class="style-control" {key}>{ component }</fieldset> })
|
|
330
331
|
})
|
|
331
332
|
.collect_vec()
|
|
332
333
|
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
2
|
+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
3
|
+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
4
|
+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
5
|
+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
6
|
+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
7
|
+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
|
8
|
+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
|
9
|
+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
|
10
|
+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
|
11
|
+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
12
|
+
|
|
13
|
+
use yew::prelude::*;
|
|
14
|
+
|
|
15
|
+
use super::save_settings::{SaveSettings, SaveSettingsProps};
|
|
16
|
+
use crate::components::window_editor::{WindowEditor, WindowEditorProps};
|
|
17
|
+
|
|
18
|
+
#[derive(PartialEq, Properties, Clone)]
|
|
19
|
+
pub struct WindowTabProps {
|
|
20
|
+
pub editor: WindowEditorProps,
|
|
21
|
+
pub save_section: SaveSettingsProps,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
#[function_component]
|
|
25
|
+
pub fn WindowTab(p: &WindowTabProps) -> Html {
|
|
26
|
+
html! {
|
|
27
|
+
<div id="window-tab">
|
|
28
|
+
<div class="tab-section" id="window-editor-section">
|
|
29
|
+
<WindowEditor ..p.editor.clone() />
|
|
30
|
+
</div>
|
|
31
|
+
<div class="tab-section"><SaveSettings ..p.save_section.clone() /></div>
|
|
32
|
+
</div>
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -13,12 +13,13 @@ mod attributes_tab;
|
|
|
13
13
|
|
|
14
14
|
mod save_settings;
|
|
15
15
|
pub(crate) mod style_tab;
|
|
16
|
+
mod window_tab;
|
|
16
17
|
|
|
17
18
|
use std::rc::Rc;
|
|
18
19
|
|
|
19
20
|
use derivative::Derivative;
|
|
20
21
|
use itertools::Itertools;
|
|
21
|
-
use perspective_client::config::{ColumnType, Expression, ViewConfig};
|
|
22
|
+
use perspective_client::config::{ColumnType, Expression, ViewConfig, WindowSpec};
|
|
22
23
|
use perspective_client::utils::PerspectiveResultExt;
|
|
23
24
|
use yew::{Callback, Component, Html, Properties, html, props};
|
|
24
25
|
|
|
@@ -27,15 +28,19 @@ use self::style_tab::StyleTabProps;
|
|
|
27
28
|
use crate::components::column_settings_sidebar::attributes_tab::AttributesTab;
|
|
28
29
|
use crate::components::column_settings_sidebar::save_settings::SaveSettingsProps;
|
|
29
30
|
use crate::components::column_settings_sidebar::style_tab::StyleTab;
|
|
31
|
+
use crate::components::column_settings_sidebar::window_tab::{WindowTab, WindowTabProps};
|
|
30
32
|
use crate::components::containers::sidebar::Sidebar;
|
|
31
33
|
use crate::components::containers::tab_list::TabList;
|
|
32
34
|
use crate::components::editable_header::EditableHeaderProps;
|
|
33
35
|
use crate::components::expression_editor::ExpressionEditorProps;
|
|
34
36
|
use crate::components::type_icon::TypeIconType;
|
|
37
|
+
use crate::components::window_editor::WindowEditorProps;
|
|
35
38
|
use crate::presentation::{ColumnLocator, ColumnSettingsTab, Presentation};
|
|
36
39
|
use crate::renderer::Renderer;
|
|
37
40
|
use crate::session::{Session, SessionMetadataRc};
|
|
38
|
-
use crate::tasks::{
|
|
41
|
+
use crate::tasks::{
|
|
42
|
+
delete_expr, delete_window, save_expr, save_window, update_expr, update_window,
|
|
43
|
+
};
|
|
39
44
|
use crate::utils::PtrEqRc;
|
|
40
45
|
|
|
41
46
|
#[derive(Clone, Derivative, Properties)]
|
|
@@ -47,9 +52,22 @@ pub struct ColumnSettingsPanelProps {
|
|
|
47
52
|
pub width_override: Option<i32>,
|
|
48
53
|
pub on_select_tab: Callback<ColumnSettingsTab>,
|
|
49
54
|
|
|
50
|
-
///
|
|
51
|
-
///
|
|
52
|
-
|
|
55
|
+
/// Shared trap-door width across the drawer's Style/Attributes/Window
|
|
56
|
+
/// tabs.
|
|
57
|
+
#[prop_or_default]
|
|
58
|
+
pub auto_width: f64,
|
|
59
|
+
|
|
60
|
+
#[prop_or_default]
|
|
61
|
+
pub on_auto_width: Callback<f64>,
|
|
62
|
+
|
|
63
|
+
/// Whether the drawer is pinned into the layout.
|
|
64
|
+
#[prop_or_default]
|
|
65
|
+
pub is_pinned: bool,
|
|
66
|
+
|
|
67
|
+
#[prop_or_default]
|
|
68
|
+
pub on_toggle_pin: Callback<()>,
|
|
69
|
+
|
|
70
|
+
/// Active plugin name.
|
|
53
71
|
pub plugin_name: Option<String>,
|
|
54
72
|
|
|
55
73
|
/// Session metadata snapshot — threaded from `SessionProps`.
|
|
@@ -75,8 +93,10 @@ pub struct ColumnSettingsPanelProps {
|
|
|
75
93
|
pub session: Session,
|
|
76
94
|
}
|
|
77
95
|
|
|
78
|
-
impl
|
|
79
|
-
|
|
96
|
+
impl ColumnSettingsPanelProps {
|
|
97
|
+
/// Everything EXCEPT the trap-door `auto_width`: the props whose change
|
|
98
|
+
/// invalidates the drafts that `initialize` rebuilds.
|
|
99
|
+
fn identity_eq(&self, other: &Self) -> bool {
|
|
80
100
|
self.selected_column == other.selected_column
|
|
81
101
|
&& self.selected_tab == other.selected_tab
|
|
82
102
|
&& self.plugin_name == other.plugin_name
|
|
@@ -87,12 +107,21 @@ impl PartialEq for ColumnSettingsPanelProps {
|
|
|
87
107
|
}
|
|
88
108
|
}
|
|
89
109
|
|
|
110
|
+
impl PartialEq for ColumnSettingsPanelProps {
|
|
111
|
+
fn eq(&self, other: &Self) -> bool {
|
|
112
|
+
self.identity_eq(other)
|
|
113
|
+
&& self.auto_width == other.auto_width
|
|
114
|
+
&& self.is_pinned == other.is_pinned
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
90
118
|
#[derive(Debug)]
|
|
91
119
|
pub enum ColumnSettingsPanelMsg {
|
|
92
120
|
SetExprValue(Rc<String>),
|
|
93
121
|
SetExprValid(bool),
|
|
94
122
|
SetHeaderValue(Option<String>),
|
|
95
123
|
SetHeaderValid(bool),
|
|
124
|
+
SetWindowValue(Option<WindowSpec>),
|
|
96
125
|
SetSelectedTab((usize, ColumnSettingsTab)),
|
|
97
126
|
OnSaveAttributes(()),
|
|
98
127
|
OnResetAttributes(()),
|
|
@@ -117,6 +146,8 @@ pub struct ColumnSettingsPanel {
|
|
|
117
146
|
reset_enabled: bool,
|
|
118
147
|
save_count: u8,
|
|
119
148
|
save_enabled: bool,
|
|
149
|
+
initial_window_value: Option<WindowSpec>,
|
|
150
|
+
window_value: Option<WindowSpec>,
|
|
120
151
|
tabs: Vec<ColumnSettingsTab>,
|
|
121
152
|
}
|
|
122
153
|
|
|
@@ -138,6 +169,8 @@ impl Component for ColumnSettingsPanel {
|
|
|
138
169
|
reset_count: 0,
|
|
139
170
|
column_name: "".to_owned(),
|
|
140
171
|
maybe_ty: None,
|
|
172
|
+
initial_window_value: None,
|
|
173
|
+
window_value: None,
|
|
141
174
|
tabs: vec![],
|
|
142
175
|
on_input: Callback::default(),
|
|
143
176
|
on_save: Callback::default(),
|
|
@@ -149,12 +182,15 @@ impl Component for ColumnSettingsPanel {
|
|
|
149
182
|
}
|
|
150
183
|
|
|
151
184
|
fn changed(&mut self, ctx: &yew::prelude::Context<Self>, old_props: &Self::Properties) -> bool {
|
|
152
|
-
|
|
185
|
+
// Only reached when props are unequal. Re-`initialize` (which wipes
|
|
186
|
+
// in-progress expression/window drafts) only on IDENTITY changes -
|
|
187
|
+
// a trap-door `auto_width` change re-renders the `Sidebar` sizer
|
|
188
|
+
// alone.
|
|
189
|
+
if !ctx.props().identity_eq(old_props) {
|
|
153
190
|
self.initialize(ctx);
|
|
154
|
-
true
|
|
155
|
-
} else {
|
|
156
|
-
false
|
|
157
191
|
}
|
|
192
|
+
|
|
193
|
+
true
|
|
158
194
|
}
|
|
159
195
|
|
|
160
196
|
fn update(&mut self, ctx: &yew::prelude::Context<Self>, msg: Self::Message) -> bool {
|
|
@@ -187,6 +223,15 @@ impl Component for ColumnSettingsPanel {
|
|
|
187
223
|
self.save_enabled_effect();
|
|
188
224
|
true
|
|
189
225
|
},
|
|
226
|
+
ColumnSettingsPanelMsg::SetWindowValue(val) => {
|
|
227
|
+
if self.window_value != val {
|
|
228
|
+
self.window_value = val;
|
|
229
|
+
self.reset_enabled = true;
|
|
230
|
+
true
|
|
231
|
+
} else {
|
|
232
|
+
false
|
|
233
|
+
}
|
|
234
|
+
},
|
|
190
235
|
ColumnSettingsPanelMsg::SetSelectedTab((_, val)) => {
|
|
191
236
|
let rerender = ctx.props().selected_tab != Some(val);
|
|
192
237
|
ctx.props().on_select_tab.emit(val);
|
|
@@ -195,19 +240,58 @@ impl Component for ColumnSettingsPanel {
|
|
|
195
240
|
ColumnSettingsPanelMsg::OnResetAttributes(()) => {
|
|
196
241
|
self.header_value.clone_from(&self.initial_header_value);
|
|
197
242
|
self.expr_value.clone_from(&self.initial_expr_value);
|
|
243
|
+
self.window_value.clone_from(&self.initial_window_value);
|
|
198
244
|
self.save_enabled = false;
|
|
199
245
|
self.reset_enabled = false;
|
|
200
246
|
self.reset_count += 1;
|
|
201
247
|
true
|
|
202
248
|
},
|
|
203
249
|
ColumnSettingsPanelMsg::OnSaveAttributes(()) => {
|
|
250
|
+
if matches!(ctx.props().selected_tab, Some(ColumnSettingsTab::Window)) {
|
|
251
|
+
if let Some(spec) = self.window_value.clone() {
|
|
252
|
+
let name = self
|
|
253
|
+
.header_value
|
|
254
|
+
.clone()
|
|
255
|
+
.unwrap_or_else(|| self.column_name.clone());
|
|
256
|
+
match &ctx.props().selected_column {
|
|
257
|
+
ColumnLocator::Window(old_name) => update_window(
|
|
258
|
+
&ctx.props().session,
|
|
259
|
+
&ctx.props().renderer,
|
|
260
|
+
&ctx.props().presentation,
|
|
261
|
+
old_name.clone(),
|
|
262
|
+
name,
|
|
263
|
+
spec.clone(),
|
|
264
|
+
),
|
|
265
|
+
_ => {
|
|
266
|
+
if let Err(err) = save_window(
|
|
267
|
+
&ctx.props().session,
|
|
268
|
+
&ctx.props().renderer,
|
|
269
|
+
&ctx.props().presentation,
|
|
270
|
+
name,
|
|
271
|
+
spec.clone(),
|
|
272
|
+
) {
|
|
273
|
+
tracing::warn!("{}", err);
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
self.initial_window_value = Some(spec);
|
|
279
|
+
self.initial_header_value.clone_from(&self.header_value);
|
|
280
|
+
self.save_enabled = false;
|
|
281
|
+
self.reset_enabled = false;
|
|
282
|
+
self.save_count += 1;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
|
|
204
288
|
let new_expr = Expression::new(
|
|
205
289
|
self.header_value.clone().map(|s| s.into()),
|
|
206
290
|
(*(self.expr_value)).clone().into(),
|
|
207
291
|
);
|
|
208
292
|
|
|
209
293
|
match &ctx.props().selected_column {
|
|
210
|
-
ColumnLocator::Table(_) => {
|
|
294
|
+
ColumnLocator::Table(_) | ColumnLocator::Window(_) => {
|
|
211
295
|
tracing::error!("Tried to save non-expression column!")
|
|
212
296
|
},
|
|
213
297
|
ColumnLocator::Expression(name) => update_expr(
|
|
@@ -244,6 +328,13 @@ impl Component for ColumnSettingsPanel {
|
|
|
244
328
|
&self.column_name,
|
|
245
329
|
)
|
|
246
330
|
.unwrap_or_log();
|
|
331
|
+
} else if ctx.props().selected_column.is_saved_window() {
|
|
332
|
+
delete_window(
|
|
333
|
+
&ctx.props().session,
|
|
334
|
+
&ctx.props().renderer,
|
|
335
|
+
&self.column_name,
|
|
336
|
+
)
|
|
337
|
+
.unwrap_or_log();
|
|
247
338
|
}
|
|
248
339
|
|
|
249
340
|
ctx.props().on_close.emit(());
|
|
@@ -253,15 +344,24 @@ impl Component for ColumnSettingsPanel {
|
|
|
253
344
|
}
|
|
254
345
|
|
|
255
346
|
fn view(&self, ctx: &yew::prelude::Context<Self>) -> Html {
|
|
347
|
+
let is_window_tab = matches!(ctx.props().selected_tab, Some(ColumnSettingsTab::Window));
|
|
348
|
+
|
|
349
|
+
let header_placeholder = if is_window_tab {
|
|
350
|
+
Rc::new(self.column_name.clone())
|
|
351
|
+
} else {
|
|
352
|
+
self.expr_value.clone()
|
|
353
|
+
};
|
|
354
|
+
|
|
256
355
|
let header_props = props!(EditableHeaderProps {
|
|
257
356
|
initial_value: self.initial_header_value.clone(),
|
|
258
|
-
placeholder:
|
|
357
|
+
placeholder: header_placeholder,
|
|
259
358
|
reset_count: self.reset_count,
|
|
260
|
-
editable: ctx.props().selected_column.is_expr()
|
|
359
|
+
editable: (ctx.props().selected_column.is_expr()
|
|
261
360
|
&& matches!(
|
|
262
361
|
ctx.props().selected_tab,
|
|
263
362
|
Some(ColumnSettingsTab::Attributes)
|
|
264
|
-
)
|
|
363
|
+
))
|
|
364
|
+
|| (ctx.props().selected_column.is_window_editable() && is_window_tab),
|
|
265
365
|
update_on_input: true,
|
|
266
366
|
icon_type: self
|
|
267
367
|
.maybe_ty
|
|
@@ -324,7 +424,26 @@ impl Component for ColumnSettingsPanel {
|
|
|
324
424
|
|
|
325
425
|
let attrs_tab = AttributesTabProps {
|
|
326
426
|
expr_editor,
|
|
327
|
-
save_section,
|
|
427
|
+
save_section: save_section.clone(),
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
let window_changed = self.window_value != self.initial_window_value
|
|
431
|
+
|| self.header_value != self.initial_header_value;
|
|
432
|
+
let window_tab = WindowTabProps {
|
|
433
|
+
editor: WindowEditorProps {
|
|
434
|
+
metadata: ctx.props().metadata.clone(),
|
|
435
|
+
initial: self.initial_window_value.clone(),
|
|
436
|
+
on_change: ctx.link().callback(ColumnSettingsPanelMsg::SetWindowValue),
|
|
437
|
+
reset_count: self.reset_count,
|
|
438
|
+
presentation: ctx.props().presentation.clone(),
|
|
439
|
+
session: ctx.props().session.clone(),
|
|
440
|
+
selected_theme: ctx.props().selected_theme.clone(),
|
|
441
|
+
},
|
|
442
|
+
save_section: SaveSettingsProps {
|
|
443
|
+
save_enabled: self.window_value.is_some() && window_changed && self.header_valid,
|
|
444
|
+
show_danger_zone: ctx.props().selected_column.is_saved_window(),
|
|
445
|
+
..save_section
|
|
446
|
+
},
|
|
328
447
|
};
|
|
329
448
|
|
|
330
449
|
let style_tab = StyleTabProps {
|
|
@@ -342,6 +461,7 @@ impl Component for ColumnSettingsPanel {
|
|
|
342
461
|
|
|
343
462
|
let tab_children = self.tabs.iter().map(|tab| match tab {
|
|
344
463
|
ColumnSettingsTab::Attributes => html! { <AttributesTab ..attrs_tab.clone() /> },
|
|
464
|
+
ColumnSettingsTab::Window => html! { <WindowTab ..window_tab.clone() /> },
|
|
345
465
|
ColumnSettingsTab::Style => html! { <StyleTab ..style_tab.clone() /> },
|
|
346
466
|
});
|
|
347
467
|
|
|
@@ -358,6 +478,10 @@ impl Component for ColumnSettingsPanel {
|
|
|
358
478
|
on_close={ctx.props().on_close.clone()}
|
|
359
479
|
id_prefix="column_settings"
|
|
360
480
|
width_override={ctx.props().width_override}
|
|
481
|
+
auto_width={ctx.props().auto_width}
|
|
482
|
+
on_auto_width={ctx.props().on_auto_width.clone()}
|
|
483
|
+
is_pinned={ctx.props().is_pinned}
|
|
484
|
+
on_toggle_pin={Some(ctx.props().on_toggle_pin.clone())}
|
|
361
485
|
selected_tab={selected_tab_idx}
|
|
362
486
|
{header_props}
|
|
363
487
|
>
|
|
@@ -403,6 +527,16 @@ impl ColumnSettingsPanel {
|
|
|
403
527
|
.metadata
|
|
404
528
|
.locator_view_type(&ctx.props().selected_column);
|
|
405
529
|
|
|
530
|
+
// Specs are unnamed (the `windows` map key names them, and the
|
|
531
|
+
// editable header owns naming in the UI), so drafts and saved specs
|
|
532
|
+
// compare directly.
|
|
533
|
+
let initial_window_value = ctx
|
|
534
|
+
.props()
|
|
535
|
+
.selected_column
|
|
536
|
+
.name()
|
|
537
|
+
.and_then(|name| ctx.props().view_config.windows.get(name))
|
|
538
|
+
.cloned();
|
|
539
|
+
|
|
406
540
|
let tabs = {
|
|
407
541
|
let mut tabs = vec![];
|
|
408
542
|
let is_new_expr = ctx.props().selected_column.is_new_expr();
|
|
@@ -424,6 +558,17 @@ impl ColumnSettingsPanel {
|
|
|
424
558
|
tabs.push(ColumnSettingsTab::Attributes);
|
|
425
559
|
}
|
|
426
560
|
|
|
561
|
+
let supports_windows = ctx
|
|
562
|
+
.props()
|
|
563
|
+
.metadata
|
|
564
|
+
.get_features()
|
|
565
|
+
.map(|x| x.has_window_aggregates())
|
|
566
|
+
.unwrap_or_default();
|
|
567
|
+
|
|
568
|
+
if ctx.props().selected_column.is_window_editable() && supports_windows {
|
|
569
|
+
tabs.push(ColumnSettingsTab::Window);
|
|
570
|
+
}
|
|
571
|
+
|
|
427
572
|
tabs
|
|
428
573
|
};
|
|
429
574
|
|
|
@@ -440,6 +585,8 @@ impl ColumnSettingsPanel {
|
|
|
440
585
|
header_value: initial_header_value.clone(),
|
|
441
586
|
initial_header_value,
|
|
442
587
|
maybe_ty,
|
|
588
|
+
window_value: initial_window_value.clone(),
|
|
589
|
+
initial_window_value,
|
|
443
590
|
tabs,
|
|
444
591
|
header_valid: true,
|
|
445
592
|
on_input,
|