perspective_viewer/components/
settings_panel.rs1use std::rc::Rc;
14
15use perspective_client::config::{ViewConfig, ViewConfigUpdate};
16use perspective_js::utils::ApiFuture;
17use yew::prelude::*;
18
19use super::column_selector::ColumnSelector;
20use super::plugin_selector::PluginSelector;
21use crate::components::containers::sidebar_close_button::SidebarCloseButton;
22use crate::config::PluginUpdate;
23use crate::dragdrop::*;
24use crate::presentation::{ColumnLocator, OpenColumnSettings, Presentation};
25use crate::renderer::*;
26use crate::session::column_defaults_update::*;
27use crate::session::*;
28use crate::tasks::can_render_column_styles;
29use crate::utils::*;
30
31#[derive(Clone, Properties)]
32pub struct SettingsPanelProps {
33 pub on_close: Callback<()>,
34 pub on_resize: Rc<PubSub<()>>,
35 pub on_select_column: Callback<ColumnLocator>,
36 pub on_debug: Callback<()>,
37 pub is_debug: bool,
38
39 pub plugin_name: Option<String>,
41 pub available_plugins: PtrEqRc<Vec<String>>,
42 pub has_table: Option<TableLoadState>,
43 pub named_column_count: usize,
44 pub view_config: PtrEqRc<ViewConfig>,
45 pub drag_column: Option<String>,
48 pub metadata: SessionMetadataRc,
51 pub open_column_settings: OpenColumnSettings,
54
55 pub selected_theme: Option<String>,
57
58 pub dragdrop: DragDrop,
60 pub session: Session,
61 pub renderer: Renderer,
62 pub presentation: Presentation,
63}
64
65impl PartialEq for SettingsPanelProps {
66 fn eq(&self, rhs: &Self) -> bool {
67 self.is_debug == rhs.is_debug
68 && self.plugin_name == rhs.plugin_name
69 && self.available_plugins == rhs.available_plugins
70 && self.has_table == rhs.has_table
71 && self.named_column_count == rhs.named_column_count
72 && self.view_config == rhs.view_config
73 && self.drag_column == rhs.drag_column
74 && self.metadata == rhs.metadata
75 && self.open_column_settings == rhs.open_column_settings
76 && self.selected_theme == rhs.selected_theme
77 }
78}
79
80#[function_component]
81pub fn SettingsPanel(props: &SettingsPanelProps) -> Html {
82 let SettingsPanelProps {
83 dragdrop,
84 presentation,
85 renderer,
86 session,
87 ..
88 } = &props;
89
90 let selected_column = {
91 let locator = props.open_column_settings.locator.clone();
92 let config = &props.view_config;
93 locator.filter(|locator| match locator {
94 ColumnLocator::Table(name) => {
95 locator
96 .name()
97 .map(|n| {
98 config.columns.iter().any(|maybe_col| {
99 maybe_col.as_ref().map(|col| col == n).unwrap_or_default()
100 }) || config.group_by.iter().any(|col| col == n)
101 || config.split_by.iter().any(|col| col == n)
102 || config.filter.iter().any(|col| col.column() == n)
103 || config.sort.iter().any(|col| &col.0 == n)
104 })
105 .unwrap_or_default()
106 && can_render_column_styles(&props.renderer, config, &props.metadata, name)
107 .unwrap_or_default()
108 },
109 _ => true,
110 })
111 };
112
113 let plugin_name = props.plugin_name.clone();
114 let available_plugins = props.available_plugins.clone();
115
116 let on_select_plugin = {
118 clone!(renderer, session, presentation);
119 let session_metadata = props.metadata.clone();
120 Callback::from(move |plugin_name: String| {
121 if !session.is_errored() {
122 let metadata =
123 renderer.get_next_plugin_metadata(&PluginUpdate::Update(plugin_name));
124
125 let prev_metadata = renderer.metadata();
126 let requirements = metadata.as_ref().unwrap_or(&*prev_metadata);
127 let rollup_features = session_metadata
128 .get_features()
129 .map(|x| x.get_group_rollup_modes())
130 .unwrap();
131
132 let group_rollups = requirements.get_group_rollups(&rollup_features);
133 let mut update = ViewConfigUpdate {
134 group_rollup_mode: group_rollups.first().cloned(),
135 ..ViewConfigUpdate::default()
136 };
137
138 update.set_update_column_defaults(
139 &session_metadata,
140 &session.get_view_config().columns,
141 requirements,
142 );
143
144 if session.update_view_config(update).is_ok() {
145 clone!(renderer, session);
146 ApiFuture::spawn(async move {
147 renderer.apply_pending_plugin()?;
148 renderer.draw(session.validate().await?.create_view()).await
149 });
150 }
151
152 presentation.set_open_column_settings(None);
153 }
154 })
155 };
156
157 html! {
158 <div id="settings_panel" class="sidebar_column noselect split-panel orient-vertical">
159 if selected_column.is_none() {
160 <SidebarCloseButton
161 id="settings_close_button"
162 on_close_sidebar={&props.on_close.clone()}
163 />
164 }
165 <SidebarCloseButton
166 id={if props.is_debug {"debug_close_button"} else {"debug_open_button"}}
167 on_close_sidebar={&props.on_debug}
168 />
169 <PluginSelector {plugin_name} {available_plugins} {on_select_plugin} />
170 <ColumnSelector
171 on_resize={&props.on_resize}
172 on_open_expr_panel={&props.on_select_column}
173 {selected_column}
174 has_table={props.has_table.clone()}
175 named_column_count={props.named_column_count}
176 view_config={props.view_config.clone()}
177 drag_column={props.drag_column.clone()}
178 metadata={props.metadata.clone()}
179 selected_theme={props.selected_theme.clone()}
180 {dragdrop}
181 renderer={renderer.clone()}
182 session={session.clone()}
183 />
184 </div>
185 }
186}