Skip to content

Commit 7a11794

Browse files
author
ada mandala
committed
retain selected tab on column manipulation; prefer passing props instead of components
1 parent a917816 commit 7a11794

File tree

11 files changed

+106
-133
lines changed

11 files changed

+106
-133
lines changed

rust/perspective-viewer/src/rust/components/column_settings_sidebar/sidebar.rs

Lines changed: 61 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,24 @@
1010
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
1111
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
1212

13-
mod tablist;
1413
use std::fmt::Display;
1514
use std::rc::Rc;
1615

1716
use derivative::Derivative;
18-
pub use tablist::*;
19-
use yew::{function_component, html, Callback, Component, Html, Properties};
17+
use itertools::Itertools;
18+
use yew::{html, Callback, Component, Html, Properties};
2019

2120
use super::attributes_tab::AttributesTabProps;
2221
use super::style_tab::StyleTabProps;
22+
use crate::components::column_settings_sidebar::attributes_tab::AttributesTab;
2323
use crate::components::column_settings_sidebar::save_settings::SaveSettingsProps;
24+
use crate::components::column_settings_sidebar::style_tab::StyleTab;
2425
use crate::components::containers::sidebar::Sidebar;
25-
use crate::components::editable_header::EditableHeader;
26+
use crate::components::containers::tab_list::{Tab, TabList};
27+
use crate::components::editable_header::EditableHeaderProps;
2628
use crate::components::expression_editor::ExpressionEditorProps;
2729
use crate::components::style::LocalStyle;
28-
use crate::components::type_icon::{TypeIcon, TypeIconType};
30+
use crate::components::type_icon::TypeIconType;
2931
use crate::components::viewer::ColumnLocator;
3032
use crate::config::{Expression, Type};
3133
use crate::custom_events::CustomEvents;
@@ -35,6 +37,13 @@ use crate::renderer::Renderer;
3537
use crate::session::Session;
3638
use crate::{css, derive_model, html_template};
3739

40+
#[derive(Debug, Default, Clone, Copy, PartialEq)]
41+
pub enum ColumnSettingsTab {
42+
#[default]
43+
Attributes,
44+
Style,
45+
}
46+
impl Tab for ColumnSettingsTab {}
3847
impl Display for ColumnSettingsTab {
3948
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4049
f.write_fmt(format_args!("{self:?}"))
@@ -87,14 +96,15 @@ pub struct ColumnSettingsSidebar {
8796
initial_header_value: Option<String>,
8897
header_value: Option<String>,
8998
header_valid: bool,
90-
selected_tab: (usize, ColumnSettingsTab),
99+
selected_tab: ColumnSettingsTab,
100+
selected_tab_idx: usize,
91101
save_enabled: bool,
92102
save_count: u8,
93103
reset_enabled: bool,
94104
reset_count: u8,
95105
column_name: String,
96106
maybe_ty: Option<Type>,
97-
tabs: Rc<Vec<ColumnSettingsTab>>,
107+
tabs: Vec<ColumnSettingsTab>,
98108
}
99109

100110
impl ColumnSettingsSidebar {
@@ -165,7 +175,7 @@ impl Component for ColumnSettingsSidebar {
165175
if ctx.props().selected_column.is_expr() {
166176
tabs.push(ColumnSettingsTab::Attributes);
167177
}
168-
Rc::new(tabs)
178+
tabs
169179
};
170180

171181
Self {
@@ -184,7 +194,15 @@ impl Component for ColumnSettingsSidebar {
184194
fn changed(&mut self, ctx: &yew::prelude::Context<Self>, old_props: &Self::Properties) -> bool {
185195
tracing::error!("Changed! {old_props:?} -> {:?}", ctx.props());
186196
if ctx.props() != old_props {
197+
let selected_tab = self.selected_tab;
187198
*self = Self::create(ctx);
199+
self.selected_tab = selected_tab;
200+
self.selected_tab_idx = self
201+
.tabs
202+
.iter()
203+
.find_position(|tab| **tab == selected_tab)
204+
.map(|(idx, _val)| idx)
205+
.unwrap_or_default();
188206
true
189207
} else {
190208
false
@@ -194,7 +212,6 @@ impl Component for ColumnSettingsSidebar {
194212
fn update(&mut self, ctx: &yew::prelude::Context<Self>, msg: Self::Message) -> bool {
195213
tracing::error!("Updated! {msg:?}");
196214
match msg {
197-
// is there a better pattern for this?
198215
ColumnSettingsMsg::SetExprValue(val) => {
199216
if self.expr_value != val {
200217
self.expr_value = val;
@@ -223,9 +240,10 @@ impl Component for ColumnSettingsSidebar {
223240
self.save_enabled_effect();
224241
true
225242
},
226-
ColumnSettingsMsg::SetSelectedTab(val) => {
227-
let rerender = self.selected_tab != val;
243+
ColumnSettingsMsg::SetSelectedTab((idx, val)) => {
244+
let rerender = self.selected_tab != val || self.selected_tab_idx != idx;
228245
self.selected_tab = val;
246+
self.selected_tab_idx = idx;
229247
rerender
230248
},
231249
ColumnSettingsMsg::OnResetAttributes(()) => {
@@ -251,6 +269,8 @@ impl Component for ColumnSettingsSidebar {
251269
},
252270
}
253271

272+
self.initial_expr_value = self.expr_value.clone();
273+
self.initial_header_value = self.header_value.clone();
254274
self.save_enabled = false;
255275
self.reset_enabled = false;
256276
self.save_count += 1;
@@ -268,27 +288,24 @@ impl Component for ColumnSettingsSidebar {
268288

269289
fn view(&self, ctx: &yew::prelude::Context<Self>) -> Html {
270290
tracing::error!("Render!");
271-
let editable = ctx.props().selected_column.is_expr()
272-
&& matches!(self.selected_tab.1, ColumnSettingsTab::Attributes);
273-
let header_icon = html! {
274-
<TypeIcon ty={self.maybe_ty.map(|ty| ty.into()).unwrap_or(TypeIconType::Expr)} />
275-
};
276-
let on_change = ctx.link().batch_callback(|(value, valid)| {
277-
vec![
278-
ColumnSettingsMsg::SetHeaderValue(value),
279-
ColumnSettingsMsg::SetHeaderValid(valid),
280-
]
281-
});
282-
let header_contents = html! {
283-
<EditableHeader
284-
icon={Some(header_icon)}
285-
{on_change}
286-
{editable}
287-
initial_value={self.initial_header_value.clone()}
288-
placeholder={self.expr_value.clone()}
289-
session={ctx.props().session.clone()}
290-
reset_count={self.reset_count}
291-
/>
291+
292+
let header_props = EditableHeaderProps {
293+
icon_type: self
294+
.maybe_ty
295+
.map(|ty| ty.into())
296+
.or(Some(TypeIconType::Expr)),
297+
on_change: ctx.link().batch_callback(|(value, valid)| {
298+
vec![
299+
ColumnSettingsMsg::SetHeaderValue(value),
300+
ColumnSettingsMsg::SetHeaderValid(valid),
301+
]
302+
}),
303+
editable: ctx.props().selected_column.is_expr()
304+
&& matches!(self.selected_tab, ColumnSettingsTab::Attributes),
305+
initial_value: self.initial_header_value.clone(),
306+
placeholder: self.expr_value.clone(),
307+
session: ctx.props().session.clone(),
308+
reset_count: self.reset_count,
292309
};
293310

294311
let expr_editor = ExpressionEditorProps {
@@ -324,28 +341,26 @@ impl Component for ColumnSettingsSidebar {
324341
column_name: self.column_name.clone(),
325342
};
326343

344+
let tab_children = self.tabs.iter().map(|tab| match tab {
345+
ColumnSettingsTab::Attributes => html! {<AttributesTab ..attrs_tab.clone()/>},
346+
ColumnSettingsTab::Style => html! {<StyleTab ..style_tab.clone()/>},
347+
});
348+
327349
html_template! {
328350
<LocalStyle href={ css!("column-settings-panel") } />
329351
<Sidebar
330352
on_close={ctx.props().on_close.clone()}
331353
id_prefix="column_settings"
332354
width_override={ctx.props().width_override}
333-
selected_tab={self.selected_tab.0}
334-
{header_contents}
355+
selected_tab={self.selected_tab_idx}
356+
{header_props}
335357
>
336-
<ColumnSettingsTablist
337-
renderer={ctx.props().renderer.clone()}
338-
presentation={ctx.props().presentation.clone()}
339-
session={ctx.props().session.clone()}
340-
custom_events={ctx.props().custom_events.clone()}
341-
342-
on_tab_change={ctx.link().callback(ColumnSettingsMsg::SetSelectedTab)}
343-
selected_tab={self.selected_tab}
358+
<TabList<ColumnSettingsTab>
344359
tabs={self.tabs.clone()}
345-
346-
{attrs_tab}
347-
{style_tab}
348-
/>
360+
on_tab_change={ctx.link().callback(ColumnSettingsMsg::SetSelectedTab)}
361+
selected_tab={self.selected_tab_idx}>
362+
{for tab_children}
363+
</TabList<ColumnSettingsTab>>
349364
</Sidebar>
350365
}
351366
}

rust/perspective-viewer/src/rust/components/column_settings_sidebar/sidebar/tablist.rs

Lines changed: 0 additions & 77 deletions
This file was deleted.

rust/perspective-viewer/src/rust/components/column_settings_sidebar/style_tab.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use yew::{function_component, html, Html, Properties};
1919
use crate::components::column_settings_sidebar::style_tab::column_style::ColumnStyle;
2020
use crate::components::column_settings_sidebar::style_tab::stub::Stub;
2121
use crate::components::column_settings_sidebar::style_tab::symbol::SymbolStyle;
22+
use crate::config::Type;
2223
use crate::custom_events::CustomEvents;
2324
use crate::renderer::Renderer;
2425
use crate::session::Session;

rust/perspective-viewer/src/rust/components/containers/sidebar.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use yew::{
1717
};
1818

1919
use crate::clone;
20+
use crate::components::editable_header::{EditableHeader, EditableHeaderProps};
2021

2122
#[derive(PartialEq, Clone, Properties)]
2223
pub struct SidebarProps {
@@ -28,7 +29,7 @@ pub struct SidebarProps {
2829
pub id_prefix: String,
2930
pub width_override: Option<i32>,
3031
pub selected_tab: Option<usize>,
31-
pub header_contents: Html,
32+
pub header_props: EditableHeaderProps,
3233
}
3334

3435
/// Sidebars are designed to live in a [SplitPanel]
@@ -65,7 +66,7 @@ pub fn Sidebar(p: &SidebarProps) -> Html {
6566
on_close_sidebar={ &p.on_close }
6667
/>
6768
<div class="sidebar_header">
68-
{p.header_contents.clone()}
69+
<EditableHeader ..p.header_props.clone()/>
6970
</div>
7071
<div class="sidebar_border" id={ format!("{id}_border") }></div>
7172
<div class="sidebar_content" id={ format!("{id}_content") }>

rust/perspective-viewer/src/rust/components/containers/tab_list.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@ impl Tab for &'static str {}
2323

2424
#[derive(Properties, Debug, PartialEq)]
2525
pub struct TabListProps<T: Tab> {
26+
// all possible tabs
2627
pub tabs: Vec<T>,
27-
pub on_tab_change: Callback<usize>,
28+
pub on_tab_change: Callback<(usize, T)>,
2829
pub selected_tab: Option<usize>,
30+
// the curently instantiated tabs
2931
pub children: Children,
3032
}
3133

@@ -52,7 +54,9 @@ impl<T: Tab> Component for TabList<T> {
5254
fn update(&mut self, ctx: &yew::Context<Self>, msg: Self::Message) -> bool {
5355
match msg {
5456
TabListMsg::SetSelected(idx) => {
55-
ctx.props().on_tab_change.emit(idx);
57+
ctx.props()
58+
.on_tab_change
59+
.emit((idx, ctx.props().tabs[idx].clone()));
5660
self.selected_idx = idx;
5761
true
5862
},

rust/perspective-viewer/src/rust/components/editable_header.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ use itertools::Itertools;
1717
use web_sys::{FocusEvent, HtmlInputElement, KeyboardEvent};
1818
use yew::{classes, function_component, html, Callback, Html, Properties, TargetCast};
1919

20+
use super::type_icon::TypeIconType;
2021
use crate::clone;
22+
use crate::components::type_icon::TypeIcon;
2123
use crate::session::Session;
2224

23-
#[derive(PartialEq, Properties, Derivative)]
25+
#[derive(PartialEq, Properties, Derivative, Clone)]
2426
#[derivative(Debug)]
2527
pub struct EditableHeaderProps {
26-
pub icon: Option<Html>,
28+
pub icon_type: Option<TypeIconType>,
2729
pub on_change: Callback<(Option<String>, bool)>,
2830
pub editable: bool,
2931
pub initial_value: Option<String>,
@@ -154,8 +156,8 @@ pub fn editable_header(p: &EditableHeaderProps) -> Html {
154156
class={classes}
155157
{onclick}
156158
>
157-
if let Some(icon) = p.icon.clone() {
158-
{icon}
159+
if let Some(icon) = p.icon_type {
160+
<TypeIcon ty={icon}/>
159161
}
160162
<input
161163
ref={noderef}

rust/perspective-viewer/src/rust/components/type_icon.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::components::style::LocalStyle;
1717
use crate::config::Type;
1818
use crate::{css, html_template};
1919

20-
#[derive(PartialEq, Debug)]
20+
#[derive(PartialEq, Debug, Clone, Copy)]
2121
pub enum TypeIconType {
2222
Type(Type),
2323
Expr,

rust/perspective-viewer/src/rust/presentation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ impl Presentation {
152152
if *(self.open_column_settings.borrow()) != settings {
153153
*(self.open_column_settings.borrow_mut()) = settings.to_owned();
154154
self.column_settings_open_changed
155-
.emit_all((true, settings.name()));
155+
.emit((true, settings.name()));
156156
}
157157
}
158158

0 commit comments

Comments
 (0)