Skip to main content

edc_web_components/components/
transfer_process_status.rs

1use 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_error = 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_error.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_error_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_error_setter = transfer_process_error_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_error_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          {
91            on_finalized.emit(());
92            break;
93          }
94
95          sleep(Duration::from_secs(1)).await;
96        }
97      });
98    },
99  );
100
101  match (
102    (*transfer_process_error).clone(),
103    (*transfer_process_state).clone(),
104  ) {
105    (Some(error_message), _) => html!(
106      <Alert title="Transfer Process failed" r#type={AlertType::Danger}>
107        <div>{ error_message }</div>
108      </Alert>
109    ),
110    (None, Some(transfer_process)) => {
111      let transfer_process: TransferProcess = transfer_process;
112
113      let current_state_index = HAPPY_PATH_STATES
114        .iter()
115        .position(|(_, state)| state == transfer_process.state())
116        .unwrap_or_default();
117
118      let steps = HAPPY_PATH_STATES
119        .iter()
120        .enumerate()
121        .map(|(index, (state_label, _))| {
122          let status = if index < current_state_index {
123            ProgressStepperStepStatus::Success
124          } else if index == current_state_index {
125            if index == HAPPY_PATH_STATES.len() - 1 {
126              ProgressStepperStepStatus::Success
127            } else {
128              ProgressStepperStepStatus::Default
129            }
130          } else {
131            ProgressStepperStepStatus::Pending
132          };
133
134          html_nested!(
135            <ProgressStepperStep {status}>
136              <div>{ state_label.to_string() }</div>
137            </ProgressStepperStep>
138          )
139        });
140
141      html!(<ProgressStepper>{ for steps }</ProgressStepper>)
142    }
143    _ => html!(),
144  }
145}