@perspective-dev/viewer 5.1.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/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 +41 -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 +41 -1
- package/dist/esm/ts-rs/ViewerConfigInitial.d.ts +175 -0
- package/dist/esm/ts-rs/ViewerConfigUpdate.d.ts +63 -0
- package/dist/esm/ts-rs/WindowSpec.d.ts +3 -2
- package/dist/esm/ts-rs/WorkspaceConfigUpdate.d.ts +7 -6
- package/dist/wasm/perspective-viewer.d.ts +134 -25
- package/dist/wasm/perspective-viewer.js +367 -124
- 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 +8 -0
- package/src/css/config-selector.css +38 -3
- package/src/css/form/code-editor.css +2 -3
- package/src/css/form/mirrored-textarea.css +81 -0
- package/src/css/viewer.css +328 -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/config_selector.rs +76 -7
- package/src/rust/components/column_selector.rs +7 -0
- package/src/rust/components/containers/dragdrop_list.rs +37 -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/mod.rs +2 -0
- package/src/rust/components/settings_panel.rs +80 -2
- package/src/rust/components/viewer/panels.rs +9 -14
- package/src/rust/components/viewer/render.rs +2 -0
- package/src/rust/components/window_editor.rs +75 -103
- 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 +13 -0
- package/src/rust/presentation.rs +8 -0
- package/src/rust/queries/get_viewer_config.rs +5 -1
- package/src/rust/session/column_defaults_update.rs +18 -0
- package/src/rust/session/metadata.rs +18 -20
- package/src/rust/session/replace_expression_update.rs +1 -0
- package/src/rust/tasks/create_panel.rs +18 -8
- package/src/rust/tasks/edit_window.rs +1 -1
- package/src/rust/tasks/restore_panel.rs +34 -17
- package/src/rust/tasks/sync_update_panels.rs +7 -23
- package/src/rust/workspace.rs +112 -20
- package/src/themes/intl/de.css +16 -0
- package/src/themes/intl/es.css +16 -0
- package/src/themes/intl/fr.css +16 -0
- package/src/themes/intl/ja.css +16 -0
- package/src/themes/intl/pt.css +16 -0
- package/src/themes/intl/zh.css +16 -0
- package/src/themes/intl.css +16 -0
- 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 +47 -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 +47 -1
- package/src/ts/ts-rs/ViewerConfigInitial.ts +164 -0
- package/src/ts/ts-rs/ViewerConfigUpdate.ts +72 -2
- package/src/ts/ts-rs/WindowSpec.ts +3 -2
- package/src/ts/ts-rs/WorkspaceConfigUpdate.ts +7 -6
- package/dist/esm/ts-rs/WindowAggregate.d.ts +0 -1
- package/src/ts/ts-rs/WindowAggregate.ts +0 -3
- /package/dist/wasm/snippets/{perspective-viewer-8a8c7d5d696b43ae → perspective-viewer-02e461f3d7062b26}/inline0.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-8a8c7d5d696b43ae → perspective-viewer-02e461f3d7062b26}/inline1.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-8a8c7d5d696b43ae → perspective-viewer-02e461f3d7062b26}/inline2.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-8a8c7d5d696b43ae → perspective-viewer-02e461f3d7062b26}/inline3.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-8a8c7d5d696b43ae → perspective-viewer-02e461f3d7062b26}/inline4.js +0 -0
- /package/dist/wasm/snippets/{perspective-viewer-8a8c7d5d696b43ae → perspective-viewer-02e461f3d7062b26}/inline5.js +0 -0
|
@@ -0,0 +1,165 @@
|
|
|
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
|
+
//! A `<textarea>` whose box is sized by its own text.
|
|
14
|
+
//!
|
|
15
|
+
//! A textarea cannot grow with its content — it scrolls at whatever height
|
|
16
|
+
//! it was given. The technique here, shared by [`CodeEditor`] and the chat
|
|
17
|
+
//! prompt, is to make the textarea a purely functional layer: it takes the
|
|
18
|
+
//! keystrokes, the selection and the caret, but paints no glyphs
|
|
19
|
+
//! (`color: transparent`). Underneath sits a `<pre>` mirror of the same
|
|
20
|
+
//! characters which IS painted and IS in flow, so the ordinary layout
|
|
21
|
+
//! engine sizes the box.
|
|
22
|
+
//!
|
|
23
|
+
//! This is deliberately not a JS measure-and-resize loop
|
|
24
|
+
//! (`scrollHeight` → inline `height`): that re-measures on a reflow it
|
|
25
|
+
//! just forced, drifts whenever font-size or the loaded font changes
|
|
26
|
+
//! without an `input` event to re-trigger it, and jitters at fractional
|
|
27
|
+
//! line heights. Here the two layers share their text metrics, so growth
|
|
28
|
+
//! is exact by construction and free at runtime.
|
|
29
|
+
//!
|
|
30
|
+
//! Consumers decide the AXES: the mirror's `white-space` governs growth,
|
|
31
|
+
//! so `pre-wrap` grows only downward (the chat prompt) while `pre` also
|
|
32
|
+
//! grows sideways (the expression editor). They also own the box —
|
|
33
|
+
//! padding, borders, min/max size — with `mirrored-textarea.css` fixing
|
|
34
|
+
//! only what MUST agree between the two layers.
|
|
35
|
+
//!
|
|
36
|
+
//! [`CodeEditor`]: super::code_editor::CodeEditor
|
|
37
|
+
|
|
38
|
+
use yew::html::IntoPropValue;
|
|
39
|
+
use yew::prelude::*;
|
|
40
|
+
|
|
41
|
+
#[derive(Clone)]
|
|
42
|
+
pub struct Mirror(pub Html);
|
|
43
|
+
|
|
44
|
+
impl PartialEq for Mirror {
|
|
45
|
+
fn eq(&self, _other: &Self) -> bool {
|
|
46
|
+
false
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
impl IntoPropValue<Mirror> for Html {
|
|
51
|
+
fn into_prop_value(self) -> Mirror {
|
|
52
|
+
Mirror(self)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
#[derive(Properties, PartialEq)]
|
|
57
|
+
pub struct MirroredTextareaProps {
|
|
58
|
+
/// `id` of the `<textarea>` itself — consumer CSS and tests key on it.
|
|
59
|
+
pub id: AttrValue,
|
|
60
|
+
|
|
61
|
+
/// The mirror's content: the same characters the textarea holds,
|
|
62
|
+
/// as plain text, or marked up (`CodeEditor` passes highlighted
|
|
63
|
+
/// spans). A stale mirror means a caret that drifts from the glyphs,
|
|
64
|
+
/// so this is re-rendered unconditionally — see [`Mirror`].
|
|
65
|
+
pub mirror: Mirror,
|
|
66
|
+
|
|
67
|
+
/// `id` of the mirror `<pre>`, for consumers that style it directly.
|
|
68
|
+
#[prop_or_default]
|
|
69
|
+
pub mirror_id: Option<AttrValue>,
|
|
70
|
+
|
|
71
|
+
/// Extra classes for the positioned container.
|
|
72
|
+
#[prop_or_default]
|
|
73
|
+
pub class: Classes,
|
|
74
|
+
|
|
75
|
+
#[prop_or_default]
|
|
76
|
+
pub textarea_ref: NodeRef,
|
|
77
|
+
|
|
78
|
+
#[prop_or_default]
|
|
79
|
+
pub mirror_ref: NodeRef,
|
|
80
|
+
|
|
81
|
+
/// The `placeholder` ATTRIBUTE, which exists for assistive tech: it
|
|
82
|
+
/// is painted transparent, because a CSS-`content` label cannot be
|
|
83
|
+
/// written into an attribute and so cannot be localized. The text a
|
|
84
|
+
/// sighted user reads comes from the mirror instead — see
|
|
85
|
+
/// [`Self::is_empty`].
|
|
86
|
+
#[prop_or_default]
|
|
87
|
+
pub placeholder: AttrValue,
|
|
88
|
+
|
|
89
|
+
/// Whether [`Self::mirror`] is empty, which the component cannot see
|
|
90
|
+
/// for itself (the mirror is opaque `Html`). Tags the mirror with
|
|
91
|
+
/// `is-empty` so a consumer's stylesheet can supply placeholder text
|
|
92
|
+
/// through `content`, and therefore through the intl label
|
|
93
|
+
/// mechanism, rather than through the untranslatable attribute.
|
|
94
|
+
#[prop_or_default]
|
|
95
|
+
pub is_empty: bool,
|
|
96
|
+
|
|
97
|
+
#[prop_or_default]
|
|
98
|
+
pub disabled: bool,
|
|
99
|
+
|
|
100
|
+
#[prop_or_default]
|
|
101
|
+
pub oninput: Callback<InputEvent>,
|
|
102
|
+
|
|
103
|
+
#[prop_or_default]
|
|
104
|
+
pub onkeydown: Callback<KeyboardEvent>,
|
|
105
|
+
|
|
106
|
+
#[prop_or_default]
|
|
107
|
+
pub onscroll: Callback<Event>,
|
|
108
|
+
|
|
109
|
+
/// Extra nodes inside the positioned container, e.g. `CodeEditor`'s
|
|
110
|
+
/// minimum-height sizer.
|
|
111
|
+
#[prop_or_default]
|
|
112
|
+
pub children: Children,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
#[function_component]
|
|
116
|
+
pub fn MirroredTextarea(props: &MirroredTextareaProps) -> Html {
|
|
117
|
+
html! {
|
|
118
|
+
<div class={classes!("mirrored-textarea", props.class.clone())}>
|
|
119
|
+
// `scrollable` is the viewer's webkit scrollbar styling: the
|
|
120
|
+
// input layer scrolls wherever a consumer lets it (the
|
|
121
|
+
// expression editor syncs its `scrollTop` to the mirror and
|
|
122
|
+
// line numbers), and is inert where it does not (the chat
|
|
123
|
+
// prompt, whose wrapper scrolls instead).
|
|
124
|
+
<textarea
|
|
125
|
+
id={props.id.clone()}
|
|
126
|
+
ref={props.textarea_ref.clone()}
|
|
127
|
+
class="mirrored-textarea-input scrollable"
|
|
128
|
+
spellcheck="false"
|
|
129
|
+
placeholder={props.placeholder.clone()}
|
|
130
|
+
disabled={props.disabled}
|
|
131
|
+
oninput={props.oninput.clone()}
|
|
132
|
+
onkeydown={props.onkeydown.clone()}
|
|
133
|
+
onscroll={props.onscroll.clone()}
|
|
134
|
+
/>
|
|
135
|
+
{ props.children.iter().collect::<Html>() }
|
|
136
|
+
<pre
|
|
137
|
+
id={props.mirror_id.clone()}
|
|
138
|
+
ref={props.mirror_ref.clone()}
|
|
139
|
+
class={classes!(
|
|
140
|
+
"mirrored-textarea-mirror",
|
|
141
|
+
props.is_empty.then_some("is-empty"),
|
|
142
|
+
)}
|
|
143
|
+
>
|
|
144
|
+
{ props.mirror.0.clone() }
|
|
145
|
+
// A trailing newline opens a line box in the textarea but
|
|
146
|
+
// not in the `<pre>` (which has no caret to place there),
|
|
147
|
+
// so the mirror would come up one line short exactly when
|
|
148
|
+
// the text is about to overflow. The space forces it.
|
|
149
|
+
{ " " }
|
|
150
|
+
</pre>
|
|
151
|
+
</div>
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
#[cfg(test)]
|
|
156
|
+
mod tests {
|
|
157
|
+
use super::*;
|
|
158
|
+
|
|
159
|
+
#[test]
|
|
160
|
+
fn mirror_never_compares_equal() {
|
|
161
|
+
let mirror = Mirror(Html::default());
|
|
162
|
+
assert!(mirror != mirror.clone());
|
|
163
|
+
assert!(Mirror(Html::default()) != Mirror(Html::default()));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -21,13 +21,14 @@ use super::plugin_selector::PluginSelector;
|
|
|
21
21
|
use super::plugin_tab::PluginTab;
|
|
22
22
|
use crate::components::containers::sidebar_close_button::SidebarCloseButton;
|
|
23
23
|
use crate::components::form::debug::DebugPanel;
|
|
24
|
-
use crate::config::PluginUpdate;
|
|
24
|
+
use crate::config::{PluginStaticConfig, PluginUpdate};
|
|
25
25
|
use crate::presentation::{ColumnLocator, OpenColumnSettings, Presentation};
|
|
26
26
|
use crate::renderer::*;
|
|
27
27
|
use crate::session::column_defaults_update::*;
|
|
28
28
|
use crate::session::*;
|
|
29
29
|
use crate::tasks::update_plugin_and_render;
|
|
30
30
|
use crate::utils::*;
|
|
31
|
+
use crate::workspace::Workspace;
|
|
31
32
|
|
|
32
33
|
#[derive(Clone, Properties)]
|
|
33
34
|
pub struct SettingsPanelProps {
|
|
@@ -42,6 +43,15 @@ pub struct SettingsPanelProps {
|
|
|
42
43
|
pub available_plugins: PtrEqRc<Vec<String>>,
|
|
43
44
|
pub has_table: Option<TableLoadState>,
|
|
44
45
|
pub named_column_count: usize,
|
|
46
|
+
|
|
47
|
+
/// The ACTIVE plugin's declared contract, threaded as a value prop so
|
|
48
|
+
/// that switching plugins re-renders the panes that read it. The
|
|
49
|
+
/// renderer handle cannot serve this: it is excluded from prop
|
|
50
|
+
/// equality (it is a handle, not a value), so a plugin swap that
|
|
51
|
+
/// leaves the view config untouched — Y Line back to Datagrid, both
|
|
52
|
+
/// of which name one column slot — would otherwise change nothing any
|
|
53
|
+
/// component compares.
|
|
54
|
+
pub plugin_static_config: Rc<PluginStaticConfig>,
|
|
45
55
|
pub view_config: PtrEqRc<ViewConfig>,
|
|
46
56
|
|
|
47
57
|
/// Snapshot of the active plugin's `plugin_config` bucket, threaded
|
|
@@ -90,6 +100,7 @@ pub struct SettingsPanelProps {
|
|
|
90
100
|
pub session: Session,
|
|
91
101
|
pub renderer: Renderer,
|
|
92
102
|
pub presentation: Presentation,
|
|
103
|
+
pub workspace: Workspace,
|
|
93
104
|
}
|
|
94
105
|
|
|
95
106
|
impl PartialEq for SettingsPanelProps {
|
|
@@ -99,6 +110,7 @@ impl PartialEq for SettingsPanelProps {
|
|
|
99
110
|
&& self.available_plugins == rhs.available_plugins
|
|
100
111
|
&& self.has_table == rhs.has_table
|
|
101
112
|
&& self.named_column_count == rhs.named_column_count
|
|
113
|
+
&& self.plugin_static_config == rhs.plugin_static_config
|
|
102
114
|
&& self.view_config == rhs.view_config
|
|
103
115
|
&& self.plugin_config == rhs.plugin_config
|
|
104
116
|
&& self.drag_column == rhs.drag_column
|
|
@@ -116,6 +128,11 @@ pub enum SelectedTab {
|
|
|
116
128
|
Query,
|
|
117
129
|
Plugin,
|
|
118
130
|
Debug,
|
|
131
|
+
|
|
132
|
+
/// The embedded LLM agent's chat panel. The variant exists in every
|
|
133
|
+
/// build; its tab button and body render only under the `llm-agent`
|
|
134
|
+
/// feature, and only once `agentConfig()` has been called.
|
|
135
|
+
Chat,
|
|
119
136
|
}
|
|
120
137
|
|
|
121
138
|
#[function_component]
|
|
@@ -186,8 +203,15 @@ pub fn SettingsPanel(props: &SettingsPanelProps) -> Html {
|
|
|
186
203
|
.unwrap();
|
|
187
204
|
|
|
188
205
|
let group_rollups = plugin_config.get_group_rollups(&rollup_features);
|
|
206
|
+
let split_rollup_features = session_metadata
|
|
207
|
+
.get_features()
|
|
208
|
+
.map(|x| x.get_split_rollup_modes())
|
|
209
|
+
.unwrap();
|
|
210
|
+
|
|
211
|
+
let split_rollups = plugin_config.get_split_rollups(&split_rollup_features);
|
|
189
212
|
let mut update = ViewConfigUpdate {
|
|
190
213
|
group_rollup_mode: group_rollups.first().cloned(),
|
|
214
|
+
split_rollup_mode: split_rollups.first().cloned(),
|
|
191
215
|
..ViewConfigUpdate::default()
|
|
192
216
|
};
|
|
193
217
|
|
|
@@ -237,6 +261,52 @@ pub fn SettingsPanel(props: &SettingsPanelProps) -> Html {
|
|
|
237
261
|
}
|
|
238
262
|
};
|
|
239
263
|
|
|
264
|
+
// The chat tab is zero-affordance until `agentConfig()` is called; the
|
|
265
|
+
// subscription re-renders this panel when that happens (and as the
|
|
266
|
+
// transcript updates while the chat body is mounted).
|
|
267
|
+
#[cfg(feature = "llm-agent")]
|
|
268
|
+
let (chat_tab_button, chat_body) = {
|
|
269
|
+
let update = use_force_update();
|
|
270
|
+
let agent = presentation.agent.clone();
|
|
271
|
+
use_effect_with((), move |_| {
|
|
272
|
+
let sub = agent
|
|
273
|
+
.on_update
|
|
274
|
+
.add_notify_listener(&Callback::from(move |_| update.force_update()));
|
|
275
|
+
|
|
276
|
+
move || drop(sub)
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
let button = if presentation.agent.is_configured() {
|
|
280
|
+
let on_select_column = props.on_select_column.clone();
|
|
281
|
+
let set_chat = {
|
|
282
|
+
let on_select_tab = props.on_select_tab.clone();
|
|
283
|
+
Callback::from(move |_: PointerEvent| {
|
|
284
|
+
on_select_tab.emit(SelectedTab::Chat);
|
|
285
|
+
on_select_column.emit(None)
|
|
286
|
+
})
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
html! {
|
|
290
|
+
<div
|
|
291
|
+
id="chat_tabbar_tab"
|
|
292
|
+
class={tab_class(selected, SelectedTab::Chat)}
|
|
293
|
+
onpointerdown={set_chat}
|
|
294
|
+
/>
|
|
295
|
+
}
|
|
296
|
+
} else {
|
|
297
|
+
html! {}
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
let body = html! {
|
|
301
|
+
<crate::components::chat_panel::ChatPanel agent={presentation.agent.clone()} />
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
(button, body)
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
#[cfg(not(feature = "llm-agent"))]
|
|
308
|
+
let (chat_tab_button, chat_body) = (html! {}, html! {});
|
|
309
|
+
|
|
240
310
|
let on_open_expr_panel = use_callback(props.on_select_column.clone(), |c, on_select| {
|
|
241
311
|
on_select.emit(Some(c))
|
|
242
312
|
});
|
|
@@ -270,6 +340,7 @@ pub fn SettingsPanel(props: &SettingsPanelProps) -> Html {
|
|
|
270
340
|
class={tab_class(selected, SelectedTab::Debug)}
|
|
271
341
|
onpointerdown={set_debug}
|
|
272
342
|
/>
|
|
343
|
+
{ chat_tab_button }
|
|
273
344
|
</div>
|
|
274
345
|
if selected == SelectedTab::Query {
|
|
275
346
|
<ColumnSelector
|
|
@@ -278,6 +349,7 @@ pub fn SettingsPanel(props: &SettingsPanelProps) -> Html {
|
|
|
278
349
|
{selected_column}
|
|
279
350
|
has_table={props.has_table.clone()}
|
|
280
351
|
named_column_count={props.named_column_count}
|
|
352
|
+
plugin_static_config={props.plugin_static_config.clone()}
|
|
281
353
|
view_config={props.view_config.clone()}
|
|
282
354
|
drag_column={props.drag_column.clone()}
|
|
283
355
|
metadata={props.metadata.clone()}
|
|
@@ -298,11 +370,14 @@ pub fn SettingsPanel(props: &SettingsPanelProps) -> Html {
|
|
|
298
370
|
// initial_width={width}
|
|
299
371
|
// on_auto_width={on_auto_width.clone()}
|
|
300
372
|
/>
|
|
373
|
+
} else if selected == SelectedTab::Chat {
|
|
374
|
+
{ chat_body }
|
|
301
375
|
} else {
|
|
302
376
|
<DebugPanel
|
|
303
377
|
{presentation}
|
|
304
378
|
{renderer}
|
|
305
379
|
{session}
|
|
380
|
+
workspace={props.workspace.clone()}
|
|
306
381
|
initial_width={width}
|
|
307
382
|
on_auto_width={on_auto_width.clone()}
|
|
308
383
|
/>
|
|
@@ -310,7 +385,10 @@ pub fn SettingsPanel(props: &SettingsPanelProps) -> Html {
|
|
|
310
385
|
// Sibling sizer keeps the panel width pinned across tab
|
|
311
386
|
// switches; lives outside the tab-body so it survives the
|
|
312
387
|
// tab subtree's unmount.
|
|
313
|
-
<div
|
|
388
|
+
<div
|
|
389
|
+
class="scroll-panel-auto-width"
|
|
390
|
+
style={format!("width:{}px", width)}
|
|
391
|
+
/>
|
|
314
392
|
</div>
|
|
315
393
|
}
|
|
316
394
|
}
|
|
@@ -27,7 +27,7 @@ use super::wiring::{
|
|
|
27
27
|
clear_active_callbacks, create_active_subscriptions, inject_active_callbacks,
|
|
28
28
|
subscribe_panel_titles,
|
|
29
29
|
};
|
|
30
|
-
use crate::config::{
|
|
30
|
+
use crate::config::{ViewerConfigInitial, ViewerConfigUpdate};
|
|
31
31
|
use crate::queries::*;
|
|
32
32
|
use crate::renderer::Renderer;
|
|
33
33
|
use crate::session::*;
|
|
@@ -216,18 +216,18 @@ impl PerspectiveViewer {
|
|
|
216
216
|
|
|
217
217
|
pub(super) fn on_new_panel(&mut self, ctx: &Context<Self>, id: String) -> bool {
|
|
218
218
|
if let Some(panel) = ctx.props().workspace.panel(&PanelId::from(id)) {
|
|
219
|
-
let table_name = panel.session.get_table().map(|t| t.get_name().to_owned())
|
|
219
|
+
let Some(table_name) = panel.session.get_table().map(|t| t.get_name().to_owned())
|
|
220
|
+
else {
|
|
221
|
+
tracing::warn!("Source panel has no `Table` to create a new panel from");
|
|
222
|
+
return false;
|
|
223
|
+
};
|
|
224
|
+
|
|
220
225
|
let elem = ctx.props().elem.clone();
|
|
221
226
|
let presentation = ctx.props().presentation.clone();
|
|
222
227
|
let workspace = ctx.props().workspace.clone();
|
|
223
228
|
let notify = ctx.link().callback(|_: ()| LayoutChanged);
|
|
224
229
|
let activate = ctx.link().callback(|id| SetActivePanel(id, None));
|
|
225
230
|
ApiFuture::spawn(async move {
|
|
226
|
-
let update = ViewerConfigUpdate {
|
|
227
|
-
table: table_name.map(TableUpdate::Update).unwrap_or_default(),
|
|
228
|
-
..Default::default()
|
|
229
|
-
};
|
|
230
|
-
|
|
231
231
|
let client = panel.session.get_client();
|
|
232
232
|
let new_id = create_panel(
|
|
233
233
|
&elem,
|
|
@@ -235,7 +235,7 @@ impl PerspectiveViewer {
|
|
|
235
235
|
&workspace,
|
|
236
236
|
¬ify,
|
|
237
237
|
None,
|
|
238
|
-
|
|
238
|
+
ViewerConfigInitial::new(table_name).into(),
|
|
239
239
|
client,
|
|
240
240
|
)
|
|
241
241
|
.await?;
|
|
@@ -273,18 +273,13 @@ impl PerspectiveViewer {
|
|
|
273
273
|
let notify = ctx.link().callback(|_: ()| LayoutChanged);
|
|
274
274
|
let activate = ctx.link().callback(|id| SetActivePanel(id, None));
|
|
275
275
|
ApiFuture::spawn(async move {
|
|
276
|
-
let update = ViewerConfigUpdate {
|
|
277
|
-
table: TableUpdate::Update(table),
|
|
278
|
-
..Default::default()
|
|
279
|
-
};
|
|
280
|
-
|
|
281
276
|
let new_id = create_panel(
|
|
282
277
|
&elem,
|
|
283
278
|
&presentation,
|
|
284
279
|
&workspace,
|
|
285
280
|
¬ify,
|
|
286
281
|
None,
|
|
287
|
-
|
|
282
|
+
ViewerConfigInitial::new(table).into(),
|
|
288
283
|
Some(client),
|
|
289
284
|
)
|
|
290
285
|
.await?;
|
|
@@ -94,6 +94,7 @@ impl PerspectiveViewer {
|
|
|
94
94
|
{available_plugins}
|
|
95
95
|
{has_table}
|
|
96
96
|
{named_column_count}
|
|
97
|
+
plugin_static_config={self.renderer_props.config.clone()}
|
|
97
98
|
{view_config}
|
|
98
99
|
plugin_config={self.renderer_props.plugin_config.clone()}
|
|
99
100
|
{drag_column}
|
|
@@ -108,6 +109,7 @@ impl PerspectiveViewer {
|
|
|
108
109
|
{presentation}
|
|
109
110
|
{renderer}
|
|
110
111
|
{session}
|
|
112
|
+
workspace={ctx.props().workspace.clone()}
|
|
111
113
|
/>
|
|
112
114
|
}
|
|
113
115
|
} else {
|