add push and pull sub-menus

tzemanovic
Jan 28, 2026, 4:42 PM
TEDT26JQBWGATVTY6HZTIOGFR6BXW2BHSUKUTXTA7HOXARRQ5D6AC

Dependencies

  • [2] D7A7MSIH allow to defer or abandon record, add buttons
  • [3] OPXFZKEB view tests setup
  • [4] 3QVNMRNM test non-empty repo app view
  • [5] MYGIBRRH wip custom theme
  • [6] 3TLPJ57B alt scroll via context and couple fixes
  • [7] JZXYSIYD channel selection!
  • [8] 5ZRDYL6K fork channel, fix recording esc key
  • [9] WAOGSCOJ very nice refactor, wip adding channels logs
  • [10] EJPSD5XO shared allowed actions conditions between update and view
  • [11] YK3MOJJL chonky refactor, wip other channels logs & diffs
  • [12] 7WCB5YQJ refactor msgs and modules
  • [13] PKLUHYE4 allow to copy change hash
  • [14] CULHFNIV add error report view
  • [15] LFEMJYYD start of to_record selection
  • [16] 5O4FWCFP add tests to_record selection and improve it
  • [17] YGZ3VCW4 add push
  • [18] ODCT4QJN add pull
  • [19] UTDTZCTX pull+push status, add info reports
  • [20] G5WLRXOD add screenshots for test
  • [21] OLT666N4 fix screenshot test to include status, fix failed test report
  • [22] WH57EHNM update tests
  • [23] LNAL3372 update iced
  • [24] SASAN2XC use nav-scrollable
  • [25] YKHE3XMW refactor diffs handling
  • [26] PTWZYQFR use nav-scrollable for repo status
  • [27] AZ5D2LQU allow to set record description
  • [28] 3XRG4BB6 rewritten nav-scrollable!
  • [29] 2SLTGWP6 add change files diffs to-record selection
  • [30] 23SFYK4Q big view refactor into a new crate
  • [31] S2NVIFXR allow to enter record msg
  • [32] 3BK22XE5 add a test for hover btn and more refactors
  • [33] UR4J677R nav for log changes and refactors
  • [34] XSZZB47U refactor stuff into lib
  • [*] 6YZAVBWU Initial commit

Change contents

  • edit in inflorescence_view/src/view.rs at line 56
    [10.487]
    [14.159]
    sub_menu: _,
  • replacement in inflorescence_view/src/view/test.rs at line 5
    [14.2347][12.3236:3299](),[3.4320][12.3236:3299]()
    use inflorescence_model::model::{ReadyState, State, SubState};
    [14.2347]
    [21.25]
    use inflorescence_model::model::{ReadyState, State, SubMenu, SubState};
  • replacement in inflorescence_view/src/view/test.rs at line 51
    [21.206][21.206:268]()
    let allowed_actions = action::get_allowed(&sub, &report);
    [21.206]
    [3.4726]
    let allowed_actions = action::get_allowed(&sub, &None, &report);
  • edit in inflorescence_view/src/view/test.rs at line 59
    [21.307]
    [21.307]
    sub_menu: None,
  • replacement in inflorescence_view/src/view/test.rs at line 90
    [21.415][21.415:477]()
    let allowed_actions = action::get_allowed(&sub, &report);
    [21.415]
    [4.104]
    let allowed_actions = action::get_allowed(&sub, &None, &report);
  • edit in inflorescence_view/src/view/test.rs at line 97
    [21.516]
    [21.516]
    sub_menu: None,
  • replacement in inflorescence_view/src/view/test.rs at line 143
    [21.624][21.624:686]()
    let allowed_actions = action::get_allowed(&sub, &report);
    [21.624]
    [5.8275]
    let allowed_actions = action::get_allowed(&sub, &None, &report);
  • edit in inflorescence_view/src/view/test.rs at line 150
    [21.725]
    [21.725]
    sub_menu: None,
  • replacement in inflorescence_view/src/view/test.rs at line 190
    [21.833][21.833:895]()
    let allowed_actions = action::get_allowed(&sub, &report);
    [21.833]
    [3.5637]
    let allowed_actions = action::get_allowed(&sub, &None, &report);
  • edit in inflorescence_view/src/view/test.rs at line 197
    [21.934]
    [21.934]
    sub_menu: None,
  • replacement in inflorescence_view/src/view/test.rs at line 256
    [21.1063][21.1063:1125]()
    let allowed_actions = action::get_allowed(&sub, &report);
    [21.1063]
    [21.1125]
    let allowed_actions = action::get_allowed(&sub, &None, &report);
    let state = State {
    window_size: WINDOW_SIZE,
    window_scale: WINDOW_SCALE,
    repo_path: repo_path.clone(),
    sub,
    allowed_actions,
    sub_menu: None,
    report,
    };
    test_view(mresults, uniq_name, view(&state), size);
    // _________________________________________________________________________
    //
    let uniq_name = "sub_menu_push";
    let repo = repo::State {
    dir_name: "path".to_string(),
    channel: "some_channel".to_string(),
    other_channels: vec![],
    untracked_files: BTreeSet::new(),
    changed_files: BTreeMap::new(),
    short_log: vec![],
    };
    let ready_state = ReadyState {
    user_id: Id::default().unwrap(),
    repo,
    selection: default(),
    navigation: default(),
    record_changes: default(),
    logs: default(),
    forking_channel_name: default(),
    to_record: default(),
    jobs: default(),
    };
    let repo_path = PathBuf::from("test/repo/path");
    let sub = SubState::Ready(ready_state);
    let report = report::Container::default();
    let sub_menu = Some(SubMenu::Push);
    let allowed_actions = action::get_allowed(&sub, &sub_menu, &report);
  • edit in inflorescence_view/src/view/test.rs at line 303
    [21.1295]
    [21.1295]
    sub_menu,
  • file addition: sub_menu_push-wgpu.png (----------)
    [20.1]
  • edit in inflorescence_model/src/model.rs at line 36
    [12.4335]
    [14.6619]
    pub sub_menu: Option<SubMenu>,
  • edit in inflorescence_model/src/model.rs at line 40
    [12.4338]
    [12.4338]
    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
    pub enum SubMenu {
    Push,
    Pull,
    }
  • replacement in inflorescence_model/src/action.rs at line 40
    [16.15390][17.4810:4820](),[17.4820][18.9646:9656]()
    Push,
    Pull,
    [16.15390]
    [10.4320]
    EnterSubMenu(model::SubMenu),
  • replacement in inflorescence_model/src/action.rs at line 102
    [15.13523][17.4821:4851](),[17.4851][18.9657:9687]()
    (Push, Push) => true,
    (Pull, Pull) => true,
    [15.13523]
    [10.5127]
    (EnterSubMenu(left), EnterSubMenu(right)) => left == right,
  • replacement in inflorescence_model/src/action.rs at line 123
    [16.15948][17.4852:4880](),[17.4880][18.9688:9716]()
    (Push, _) => false,
    (Pull, _) => false,
    [16.15948]
    [10.5587]
    (EnterSubMenu(_), _) => false,
  • edit in inflorescence_model/src/action.rs at line 129
    [14.6884]
    [14.6884]
    sub_menu: &Option<model::SubMenu>,
  • replacement in inflorescence_model/src/action.rs at line 132
    [14.6936][14.6936:6973](),[14.6973][10.5676:5862](),[10.5676][10.5676:5862]()
    let mut bindings = match state {
    model::SubState::Loading { .. } => vec![],
    model::SubState::SelectingId { .. } => todo!(),
    model::SubState::Ready(ready_state) => get_ready_allowed(ready_state),
    [14.6936]
    [14.6974]
    let mut bindings = if let Some(sub_menu) = sub_menu {
    match sub_menu {
    model::SubMenu::Push => {
    // TODO add options
    vec![confirm("confirm push"), cancel()]
    }
    model::SubMenu::Pull => {
    // TODO add options
    vec![confirm("confirm pull"), cancel()]
    }
    }
    } else {
    match state {
    model::SubState::Loading { .. } => vec![],
    model::SubState::SelectingId { .. } => todo!(),
    model::SubState::Ready(ready_state) => {
    get_ready_allowed(ready_state)
    }
    }
  • edit in inflorescence_model/src/action.rs at line 284
    [10.8320][10.8320:8407](),[10.8407][12.8403:8444](),[12.8444][10.8440:8447](),[10.8440][10.8440:8447]()
    let confirm = |label: &'static str| Binding {
    key: "Enter",
    label,
    msg: Some(FilteredMsg::Confirm),
    };
  • edit in inflorescence_model/src/action.rs at line 289
    [10.8565][10.8565:8640](),[10.8640][12.8445:8485](),[12.8485][10.8672:8679](),[10.8672][10.8672:8679]()
    let cancel = || Binding {
    key: "Esc",
    label: "cancel",
    msg: Some(FilteredMsg::Cancel),
    };
  • replacement in inflorescence_model/src/action.rs at line 348
    [17.4950][19.5860:5912]()
    msg: can_push.then_some(FilteredMsg::Push),
    [17.4950]
    [17.4988]
    msg: can_push
    .then_some(FilteredMsg::EnterSubMenu(model::SubMenu::Push)),
  • replacement in inflorescence_model/src/action.rs at line 354
    [18.9786][19.5976:6028]()
    msg: can_pull.then_some(FilteredMsg::Pull),
    [18.9786]
    [18.9824]
    msg: can_pull
    .then_some(FilteredMsg::EnterSubMenu(model::SubMenu::Pull)),
  • edit in inflorescence_model/src/action.rs at line 580
    [10.13330]
    [10.13330]
    // ____________________________________________________________________________
    // Simplified state used for determining allowed bindings
  • edit in inflorescence_model/src/action.rs at line 947
    [10.23202]
    // ____________________________________________________________________________
    // Bindings
    fn confirm(label: &'static str) -> Binding {
    Binding {
    key: "Enter",
    label,
    msg: Some(FilteredMsg::Confirm),
    }
    }
    fn cancel() -> Binding {
    Binding {
    key: "Esc",
    label: "cancel",
    msg: Some(FilteredMsg::Cancel),
    }
    }
  • edit in inflorescence/src/main.rs at line 124
    [10.23774]
    [14.7334]
    sub_menu: None,
  • replacement in inflorescence/src/main.rs at line 182
    [10.24296][14.7381:7483]()
    state.model.allowed_actions =
    action::get_allowed(&state.model.sub, &state.model.report);
    [10.24296]
    [10.24365]
    state.model.allowed_actions = action::get_allowed(
    &state.model.sub,
    &state.model.sub_menu,
    &state.model.report,
    );
  • replacement in inflorescence/src/main.rs at line 344
    [12.12794][9.82966:83003](),[10.25605][9.82966:83003](),[7.18123][9.82966:83003]()
    if let Some(ReadyState {
    [12.12794]
    [9.83003]
    if let Some(sub_menu) = &state.model.sub_menu {
    match sub_menu {
    model::SubMenu::Push => push(state),
    model::SubMenu::Pull => pull(state),
    }
    } else if let Some(ReadyState {
  • edit in inflorescence/src/main.rs at line 391
    [8.6809]
    [7.18549]
    Task::none()
    } else {
    Task::none()
  • edit in inflorescence/src/main.rs at line 395
    [7.18563][7.18563:18588]()
    Task::none()
  • replacement in inflorescence/src/main.rs at line 397
    [12.12836][9.83858:83895](),[10.25639][9.83858:83895](),[7.18628][9.83858:83895]()
    if let Some(ReadyState {
    [12.12836]
    [9.83895]
    if state.model.sub_menu.is_some() {
    state.model.sub_menu = None;
    } else if let Some(ReadyState {
  • replacement in inflorescence/src/main.rs at line 570
    [17.5576][17.5576:5615](),[17.5615][19.6913:7379]()
    action::FilteredMsg::Push => {
    if let Some(ReadyState { repo, jobs, .. }) =
    model::is_ready_mut(&mut state.model)
    {
    jobs.insert(model::Job::Push {
    channel: repo.channel.clone(),
    });
    state
    .repo_tx_in
    .send(repo::MsgIn::Push {
    channel: repo.channel.clone(),
    })
    .unwrap();
    }
    [17.5576]
    [15.18160]
    action::FilteredMsg::EnterSubMenu(sub_menu) => {
    state.model.sub_menu = Some(sub_menu);
  • edit in inflorescence/src/main.rs at line 574
    [15.18195][18.9937:9976](),[18.9976][19.7380:7846](),[19.7846][18.10106:10141](),[18.10106][18.10106:10141]()
    action::FilteredMsg::Pull => {
    if let Some(ReadyState { repo, jobs, .. }) =
    model::is_ready_mut(&mut state.model)
    {
    jobs.insert(model::Job::Pull {
    channel: repo.channel.clone(),
    });
    state
    .repo_tx_in
    .send(repo::MsgIn::Pull {
    channel: repo.channel.clone(),
    })
    .unwrap();
    }
    Task::none()
    }
  • edit in inflorescence/src/main.rs at line 687
    [11.64717]
    [13.2206]
    }
    fn push(state: &mut State) -> Task<Msg> {
    if let Some(ReadyState { repo, jobs, .. }) =
    model::is_ready_mut(&mut state.model)
    {
    jobs.insert(model::Job::Push {
    channel: repo.channel.clone(),
    });
    state
    .repo_tx_in
    .send(repo::MsgIn::Push {
    channel: repo.channel.clone(),
    })
    .unwrap();
    }
    state.model.sub_menu = None;
    Task::none()
  • edit in inflorescence/src/main.rs at line 707
    [13.2209]
    [13.2209]
    fn pull(state: &mut State) -> Task<Msg> {
    if let Some(ReadyState { repo, jobs, .. }) =
    model::is_ready_mut(&mut state.model)
    {
    jobs.insert(model::Job::Pull {
    channel: repo.channel.clone(),
    });
    state
    .repo_tx_in
    .send(repo::MsgIn::Pull {
    channel: repo.channel.clone(),
    })
    .unwrap();
    }
    state.model.sub_menu = None;
    Task::none()
    }
  • replacement in inflorescence/src/main.rs at line 1693
    [2.2363][18.10308:10445]()
    "f" if mods == Modifiers::SHIFT => {
    action(action::FilteredMsg::Pull)
    }
    [6.128]
    [10.29022]
    "f" if mods == Modifiers::SHIFT => action(
    action::FilteredMsg::EnterSubMenu(model::SubMenu::Pull),
    ),
  • replacement in inflorescence/src/main.rs at line 1708
    [10.29677][17.6027:6164]()
    "p" if mods == Modifiers::SHIFT => {
    action(action::FilteredMsg::Push)
    }
    [10.29677]
    [15.18398]
    "p" if mods == Modifiers::SHIFT => action(
    action::FilteredMsg::EnterSubMenu(model::SubMenu::Push),
    ),