fission_core/
navigation.rs1use crate::{Action, ActionId};
4use fission_ir::Hyperlink;
5use lazy_static::lazy_static;
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10pub enum NavigationCommand {
11 Push(String),
13 Replace(String),
15 Open(Hyperlink),
17 Back,
19 Forward,
21 Go(i32),
23 Reload,
25}
26
27#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
29pub struct NavigationRequested {
30 pub command: NavigationCommand,
32}
33
34impl NavigationRequested {
35 pub fn new(command: NavigationCommand) -> Self {
36 Self { command }
37 }
38}
39
40impl Action for NavigationRequested {
41 fn static_id() -> ActionId {
42 lazy_static! {
43 static ref ID: ActionId = ActionId::from_name("fission_core::NavigationRequested");
44 }
45 *ID
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52 use crate::{LinkTarget, Runtime, WidgetId};
53
54 #[test]
55 fn built_in_navigation_action_queues_without_an_application_reducer() {
56 let mut runtime = Runtime::default();
57 let command =
58 NavigationCommand::Open(Hyperlink::new("/projects/42").target(LinkTarget::NewWindow));
59
60 runtime
61 .dispatch(
62 NavigationRequested::new(command.clone()).into(),
63 WidgetId::explicit("projects.link"),
64 )
65 .expect("built-in navigation action should dispatch");
66
67 assert_eq!(runtime.take_pending_navigation(), vec![command]);
68 }
69
70 #[test]
71 fn navigation_action_round_trips_complete_hyperlink_metadata() {
72 let request = NavigationRequested::new(NavigationCommand::Open(
73 Hyperlink::new("/report")
74 .target(LinkTarget::Named("preview".into()))
75 .rel("alternate")
76 .download("report.pdf"),
77 ));
78 let envelope: crate::ActionEnvelope = request.clone().into();
79
80 assert_eq!(
81 serde_json::from_slice::<NavigationRequested>(&envelope.payload).unwrap(),
82 request
83 );
84 }
85}