192 lines
7.4 KiB
Rust
192 lines
7.4 KiB
Rust
use super::filetree_selection::{FileTreeSelectionReducerContract, FileTreeSelectionState};
|
|||
|
|
use super::focus_state::PageFocusKeyboardReducerContract;
|
||
|
|
use super::picker_state::PickerStateReducerContract;
|
||
|
|
use serde::Serialize;
|
||
|
|
use std::collections::BTreeSet;
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
|
||
|
|
#[serde(rename_all = "camelCase")]
|
||
|
|
pub enum TreeShellRendererMode {
|
||
|
|
Page,
|
||
|
|
FileTree,
|
||
|
|
Picker,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||
|
|
#[serde(rename_all = "camelCase")]
|
||
|
|
pub struct TreeShellRendererInput {
|
||
|
|
pub mode: TreeShellRendererMode,
|
||
|
|
pub projection_item_ids: Vec<String>,
|
||
|
|
pub expanded_ids: BTreeSet<String>,
|
||
|
|
pub focused_id: Option<String>,
|
||
|
|
pub page_focus_keyboard_reducer: Option<PageFocusKeyboardReducerContract>,
|
||
|
|
pub filetree_selection: FileTreeSelectionState,
|
||
|
|
pub filetree_selection_reducer: Option<FileTreeSelectionReducerContract>,
|
||
|
|
pub active_picker_item: Option<String>,
|
||
|
|
pub excluded_picker_ids: BTreeSet<String>,
|
||
|
|
pub picker_state_reducer: Option<PickerStateReducerContract>,
|
||
|
|
pub command_dispatcher: TreeShellCommandDispatcher,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||
|
|
#[serde(rename_all = "camelCase")]
|
||
|
|
pub struct TreeShellCommandDispatcher {
|
||
|
|
pub channel: String,
|
||
|
|
pub command_names: BTreeSet<String>,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl TreeShellRendererInput {
|
||
|
|
pub fn page(input: PageTreeRendererInput) -> Self {
|
||
|
|
Self {
|
||
|
|
mode: TreeShellRendererMode::Page,
|
||
|
|
projection_item_ids: input.projection_item_ids,
|
||
|
|
expanded_ids: input.expanded_ids,
|
||
|
|
focused_id: input.focused_id,
|
||
|
|
page_focus_keyboard_reducer: Some(PageFocusKeyboardReducerContract::default()),
|
||
|
|
filetree_selection: FileTreeSelectionState::default(),
|
||
|
|
filetree_selection_reducer: None,
|
||
|
|
active_picker_item: None,
|
||
|
|
excluded_picker_ids: BTreeSet::new(),
|
||
|
|
picker_state_reducer: None,
|
||
|
|
command_dispatcher: input.command_dispatcher,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn filetree(input: FileTreeRendererInput) -> Self {
|
||
|
|
Self {
|
||
|
|
mode: TreeShellRendererMode::FileTree,
|
||
|
|
projection_item_ids: input.projection_item_ids,
|
||
|
|
expanded_ids: input.expanded_ids,
|
||
|
|
focused_id: input.filetree_selection.focused_row_id.clone(),
|
||
|
|
page_focus_keyboard_reducer: None,
|
||
|
|
filetree_selection: input.filetree_selection,
|
||
|
|
filetree_selection_reducer: Some(FileTreeSelectionReducerContract::default()),
|
||
|
|
active_picker_item: None,
|
||
|
|
excluded_picker_ids: BTreeSet::new(),
|
||
|
|
picker_state_reducer: None,
|
||
|
|
command_dispatcher: input.command_dispatcher,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn picker(input: PickerRendererInput) -> Self {
|
||
|
|
Self {
|
||
|
|
mode: TreeShellRendererMode::Picker,
|
||
|
|
projection_item_ids: input.projection_item_ids,
|
||
|
|
expanded_ids: input.expanded_ids,
|
||
|
|
focused_id: input.active_picker_item.clone(),
|
||
|
|
page_focus_keyboard_reducer: None,
|
||
|
|
filetree_selection: FileTreeSelectionState::default(),
|
||
|
|
filetree_selection_reducer: None,
|
||
|
|
active_picker_item: input.active_picker_item,
|
||
|
|
excluded_picker_ids: input.excluded_picker_ids,
|
||
|
|
picker_state_reducer: Some(PickerStateReducerContract::default()),
|
||
|
|
command_dispatcher: input.command_dispatcher,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||
|
|
pub struct PageTreeRendererInput {
|
||
|
|
pub projection_item_ids: Vec<String>,
|
||
|
|
pub expanded_ids: BTreeSet<String>,
|
||
|
|
pub focused_id: Option<String>,
|
||
|
|
pub command_dispatcher: TreeShellCommandDispatcher,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||
|
|
pub struct FileTreeRendererInput {
|
||
|
|
pub projection_item_ids: Vec<String>,
|
||
|
|
pub expanded_ids: BTreeSet<String>,
|
||
|
|
pub filetree_selection: FileTreeSelectionState,
|
||
|
|
pub command_dispatcher: TreeShellCommandDispatcher,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||
|
|
pub struct PickerRendererInput {
|
||
|
|
pub projection_item_ids: Vec<String>,
|
||
|
|
pub expanded_ids: BTreeSet<String>,
|
||
|
|
pub active_picker_item: Option<String>,
|
||
|
|
pub excluded_picker_ids: BTreeSet<String>,
|
||
|
|
pub command_dispatcher: TreeShellCommandDispatcher,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[cfg(test)]
|
||
|
|
mod tests {
|
||
|
|
use super::{
|
||
|
|
FileTreeRendererInput, PageTreeRendererInput, PickerRendererInput, TreeShellCommandDispatcher,
|
||
|
|
TreeShellRendererInput, TreeShellRendererMode,
|
||
|
|
};
|
||
|
|
use crate::tree_shell::filetree_selection::FileTreeSelectionState;
|
||
|
|
use std::collections::BTreeSet;
|
||
|
|
|
||
|
|
fn set(values: &[&str]) -> BTreeSet<String> {
|
||
|
|
values.iter().map(|value| (*value).to_string()).collect()
|
||
|
|
}
|
||
|
|
|
||
|
|
fn dispatcher() -> TreeShellCommandDispatcher {
|
||
|
|
TreeShellCommandDispatcher {
|
||
|
|
channel: "mnote.tree.shell".into(),
|
||
|
|
command_names: set(&["tree.node.create", "tree.resource.move"]),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn tree_shell_renderer_input_contract_covers_page_filetree_and_picker_state() {
|
||
|
|
let page = TreeShellRendererInput::page(PageTreeRendererInput {
|
||
|
|
projection_item_ids: vec!["doc:root".into()],
|
||
|
|
expanded_ids: set(&["doc:root"]),
|
||
|
|
focused_id: Some("doc:root".into()),
|
||
|
|
command_dispatcher: dispatcher(),
|
||
|
|
});
|
||
|
|
assert_eq!(page.mode, TreeShellRendererMode::Page);
|
||
|
|
assert_eq!(page.focused_id.as_deref(), Some("doc:root"));
|
||
|
|
assert_eq!(page.command_dispatcher.channel, "mnote.tree.shell");
|
||
|
|
assert_eq!(
|
||
|
|
page.page_focus_keyboard_reducer
|
||
|
|
.as_ref()
|
||
|
|
.map(|contract| contract.contract_name),
|
||
|
|
Some("rust_page_focus_keyboard_reducer_v1")
|
||
|
|
);
|
||
|
|
|
||
|
|
let mut selection = FileTreeSelectionState::from_selected(&["asset:a".into()]);
|
||
|
|
selection.focused_row_id = Some("asset:a".into());
|
||
|
|
let filetree = TreeShellRendererInput::filetree(FileTreeRendererInput {
|
||
|
|
projection_item_ids: vec!["doc:root".into(), "asset:a".into()],
|
||
|
|
expanded_ids: set(&["doc:root"]),
|
||
|
|
filetree_selection: selection,
|
||
|
|
command_dispatcher: dispatcher(),
|
||
|
|
});
|
||
|
|
assert_eq!(filetree.mode, TreeShellRendererMode::FileTree);
|
||
|
|
assert_eq!(filetree.focused_id.as_deref(), Some("asset:a"));
|
||
|
|
assert!(filetree.filetree_selection.selected_row_ids.contains("asset:a"));
|
||
|
|
assert!(filetree.page_focus_keyboard_reducer.is_none());
|
||
|
|
assert_eq!(
|
||
|
|
filetree
|
||
|
|
.filetree_selection_reducer
|
||
|
|
.as_ref()
|
||
|
|
.map(|contract| contract.contract_name),
|
||
|
|
Some("rust_filetree_selection_reducer_v1")
|
||
|
|
);
|
||
|
|
|
||
|
|
let picker = TreeShellRendererInput::picker(PickerRendererInput {
|
||
|
|
projection_item_ids: vec!["doc:root".into(), "doc:child".into()],
|
||
|
|
expanded_ids: set(&["doc:root"]),
|
||
|
|
active_picker_item: Some("doc:child".into()),
|
||
|
|
excluded_picker_ids: set(&["doc:archived"]),
|
||
|
|
command_dispatcher: dispatcher(),
|
||
|
|
});
|
||
|
|
assert_eq!(picker.mode, TreeShellRendererMode::Picker);
|
||
|
|
assert_eq!(picker.focused_id.as_deref(), Some("doc:child"));
|
||
|
|
assert!(picker.excluded_picker_ids.contains("doc:archived"));
|
||
|
|
assert!(picker.page_focus_keyboard_reducer.is_none());
|
||
|
|
assert!(picker.filetree_selection_reducer.is_none());
|
||
|
|
assert_eq!(
|
||
|
|
picker
|
||
|
|
.picker_state_reducer
|
||
|
|
.as_ref()
|
||
|
|
.map(|contract| contract.contract_name),
|
||
|
|
Some("rust_picker_state_reducer_v1")
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|