edc_web_components/components/
transfer_process_status.rs1use crate::contexts::use_edc_connector_context;
2use edc_connector_client::types::transfer_process::{TransferProcess, TransferProcessState};
3use patternfly_yew::prelude::*;
4use std::time::Duration;
5use yew::platform::spawn_local;
6use yew::platform::time::sleep;
7use yew::prelude::*;
8
9const HAPPY_PATH_STATES: [(&str, TransferProcessState); 5] = [
10 ("Initial", TransferProcessState::Initial),
11 ("Provisioned", TransferProcessState::Provisioned),
12 ("Requested", TransferProcessState::Requested),
13 ("Started", TransferProcessState::Started),
14 ("Completed", TransferProcessState::Completed),
15];
16
17#[derive(Clone, Debug, PartialEq, Properties)]
18pub struct TransferProcessStatusProps {
19 pub transfer_process_id: String,
20 #[prop_or_default]
21 pub on_started: Callback<()>,
22 #[prop_or_default]
23 pub on_finalized: Callback<()>,
24}
25
26#[component]
27pub fn TransferProcessStatus(props: &TransferProcessStatusProps) -> Html {
28 let edc_connector_client = use_edc_connector_context();
29
30 let transfer_process_state = use_state(|| None);
31 let transfer_process_message = use_state(|| Option::<String>::None);
32
33 use_effect_with(
34 (
35 props.transfer_process_id.clone(),
36 edc_connector_client.clone(),
37 transfer_process_state.setter(),
38 transfer_process_message.setter(),
39 props.on_finalized.clone(),
40 props.on_started.clone(),
41 ),
42 |(
43 transfer_process_id,
44 edc_connector_client,
45 transfer_process_state_setter,
46 transfer_process_message_setter,
47 on_finalized,
48 on_started,
49 )| {
50 let transfer_process_id = transfer_process_id.clone();
51 let edc_connector_client = edc_connector_client.clone();
52 let transfer_process_state_setter = transfer_process_state_setter.clone();
53 let transfer_process_message_setter = transfer_process_message_setter.clone();
54 let on_finalized = on_finalized.clone();
55 let on_started = on_started.clone();
56
57 spawn_local(async move {
58 loop {
59 let transfer_process = if let Some(client) = edc_connector_client.get_client() {
60 client
61 .transfer_processes(edc_connector_client::EdcConnectorApiVersion::V4)
62 .get(&transfer_process_id)
63 .await
64 .ok()
65 } else {
66 None
67 };
68
69 let state = transfer_process
70 .as_ref()
71 .map(|transfer_process| transfer_process.state().clone());
72
73 let error_message = transfer_process.as_ref().and_then(|transfer_process| {
74 transfer_process
75 .error_detail()
76 .map(|error_detail| error_detail.to_string())
77 });
78
79 transfer_process_message_setter.set(error_message);
80
81 transfer_process_state_setter.set(transfer_process);
82
83 if state == Some(TransferProcessState::Started) {
84 on_started.emit(());
85 break;
86 }
87
88 if state == Some(TransferProcessState::Completed)
89 || state == Some(TransferProcessState::Terminated)
90 || state == Some(TransferProcessState::Suspended)
91 {
92 on_finalized.emit(());
93 break;
94 }
95
96 sleep(Duration::from_secs(1)).await;
97 }
98 });
99 },
100 );
101
102 match (
103 (*transfer_process_message).clone(),
104 (*transfer_process_state).clone(),
105 ) {
106 (Some(message), Some(transfer_process)) => {
107 let (title, r#type) = if transfer_process.state() == &TransferProcessState::Terminated {
108 ("Transfer Process failed", AlertType::Danger)
109 } else {
110 ("Transfer Process suspended", AlertType::Warning)
111 };
112
113 html!(
114 <Alert {title} {r#type}>
115 <div>{ message }</div>
116 </Alert>
117 )
118 }
119 (None, Some(transfer_process)) => {
120 let transfer_process: TransferProcess = transfer_process;
121
122 let current_state_index = HAPPY_PATH_STATES
123 .iter()
124 .position(|(_, state)| state == transfer_process.state())
125 .unwrap_or_default();
126
127 let steps = HAPPY_PATH_STATES
128 .iter()
129 .enumerate()
130 .map(|(index, (state_label, _))| {
131 let status = if index < current_state_index {
132 ProgressStepperStepStatus::Success
133 } else if index == current_state_index {
134 if index == HAPPY_PATH_STATES.len() - 1 {
135 ProgressStepperStepStatus::Success
136 } else {
137 ProgressStepperStepStatus::Default
138 }
139 } else {
140 ProgressStepperStepStatus::Pending
141 };
142
143 html_nested!(
144 <ProgressStepperStep {status}>
145 <div>{ state_label.to_string() }</div>
146 </ProgressStepperStep>
147 )
148 });
149
150 html!(<ProgressStepper>{ for steps }</ProgressStepper>)
151 }
152 _ => html!(),
153 }
154}